1
votes

I am new to Prolog and trying to implement a sort of a deep square predicate, which squares all the numbers in the list and also in the sublists. I wrote some sort of a working code but its not giving me the output i expect.

Code:

dsquare([],S).
dsquare([H|T],[R|S]):- number(H), dsquare(T,S), R is H*H, !.
dsquare([H|T],S):- isList(H), dsquare(H,S).
dsquare([H|T],[R|S]) :- dsquare(T,S), R = H, !.

Current Output:

2?- dsquare([[2],4,a],X).

X = [4| _VDHV] ;

X = [[2], 16, a| _VDNM] ;

fail.

Expected Output:

X = [[4], 16, a]

Also i wanted to know why am i getting those '_VDHV' and '_VDNM' in my output. Any help would be much appreciated.

Edit: ok so I updated my code as:

dsquare([],[]).
dsquare([H|T],[R|S]):- number(H), R is H*H, dsquare(T,S).
dsquare([H|T],[R|S]):- isList(H), dsquare(H,R), dsquare(T,S).
dsquare([H|T],[R|S]) :- R=H, dsquare(T,S).

but the output that I get is:

13?- dsquare([a,3,[[2]],b,4],X).

X = [a, 9, [[4]], b, 16] ;

X = [a, 9, [[4]], b, 4] ;

X = [a, 9, [[2]], b, 16] ;

X = [a, 9, [[2]], b, 4] ;

X = [a, 9, [[2]], b, 16] ;

X = [a, 9, [[2]], b, 4] ;

X = [a, 9, [[2]], b, 16] ;

X = [a, 9, [[2]], b, 4] ;

X = [a, 3, [[4]], b, 16] ;

X = [a, 3, [[4]], b, 4] ;

X = [a, 3, [[2]], b, 16] ;

X = [a, 3, [[2]], b, 4] ;

X = [a, 3, [[2]], b, 16] ;

X = [a, 3, [[2]], b, 4] ;

X = [a, 3, [[2]], b, 16] ;

X = [a, 3, [[2]], b, 4] ;

fail.

I have no clue how it gets so many results.

Edit finally the working solution is

dsquare([],[]).
dsquare([H|T],[R|S]) :- number(H), !, R is H*H, dsquare(T,S).
dsquare([H|T],[R|S]) :- isList(H), !, dsquare(H,R), dsquare(T,S).
dsquare([H|T],[H|S]) :- dsquare(T,S).
2
@CapelliC: just had to restart my program to get it to run. - Harsh Shah
@Nicholas Carey: your explanation helped a lot - Harsh Shah

2 Answers

1
votes

your Prolog should warn you about a 'singleton' in your first and third rules.

Try

dsquare([],[]).
...
dsquare([H|T],[S|R]):- isList(H), dsquare(H,S), dsquare(T,R).

OT don't place cuts without a motivated reason.

edit you get more results beacuse the last rule get fired on backtracking. Now could be the time to place the cuts where needed (i.e. after the code entered a branch guarded by a condition):

dsquare([],[]).
dsquare([H|T],[R|S]) :- number(H), !, R is H*H, dsquare(T,S).
dsquare([H|T],[R|S]) :- isList(H), !, dsquare(H,R), dsquare(T,S).
dsquare([H|T],[R|S]) :- R=H, dsquare(T,S).

or consider a refactoring that accounts for repeated code:

dsquare([],[]).
dsquare([H|T],[R|S]) :-
  (  number(H)
  -> R is H*H
  ;  isList(H)
  -> dsquare(H,R)
  ;  R=H
  ),
  dsquare(T,S).

edit the above definition (I tested that with 'if/then/else') seems fine:

1 ?- dsquare([[2],4,a],X).
X = [[4], 16, a].

2 ?- dsquare([a,[3],[[[5]]],[2],a],X).
X = [a, [9], [[[25]]], [4], a].
0
votes

The _Vxxx bits are prolog's representation of an unbound variable in the result. Basically, it's key or address in the symbol table.

  • In your first rule,

    dsquare([],S).
    

    you're never binding anything to the second argument. That means if you invoke it as dsquare([],X), X will remain unbound. And if invoked as dsquare([1,2,3],X) (assuming everything else was working properly, the resulting list structure would be broken and X would be something like [1,2,3|_VD3DC], since the very last item would be neither the atome [] (the empty list) or ./2, the structue that is a non-empty list.

  • In your second rule,

    dsquare([H|T],[R|S]):- number(H), dsquare(T,S), R is H*H, !.
    
    • The cut (!) is unnecessary
    • your order of operators in incorrect. Square H first, then recurse down. That accomplishes two things: it (A) fails early (if the result is bound), and (B) allows tail-recursion optimization to be applied.
  • In your 3rd rule,

    dsquare([H|T],S):- isList(H), dsquare(H,S).
    

    You are recursing down on the sublist that is the head of the source list, but not evaluating the tail of the source list at all and instead simply discard it.

  • In your 4th rule,

    dsquare([H|T],[R|S]) :- dsquare(T,S), R = H, !.
    

    again, as in your second rule, the cut is unneeded and the order of operations reversed.

I'd write it something like this:

deep_square( []     , []     )    % squaring an empty list produces an empty list
  .
deep_square( [X|Xs] , [Y|Ys] ) :- % otherwise...
  number(X) ,                     % if the head is a number,
  Y is X*X  ,                     % square it
  deep_square(Xs,Ys)              % and recurse down
  .                               %
deep_square( [X|Xs] , [Y|Ys] ) :- % otherwise...
  nonvar(X) ,                     % if the head is bound,
  X = [_|_] ,                     % and is a non-empty list.
  deep_square( X , Y ) ,          % deep square the head
  deep_square( Xs , Ys )          % and then recurse down
  .
deep_square( [X|Xs] , [X|Ys] ) :- % otherwise the head is unbound or something other than a number or a non-empty list...
  deep_square( Xs , Ys )          % recurse down.
  .                               % Easy!

You'll notice that there is a lot of unification magick and suchlike that happens in the heads of the clauses of a prolog predicate.