3
votes

How does one evaluate the result of a prolog predicate to pass as an argument? I am trying to write code to reverse pairs of elements in a list:

swap([A,B,C,D,E,F],R).

I want the result:

[B,A,D,C,F,E]

but I get this result:

append(append(append([],[B,A],[D,C],[F,E])))

Here is my code:

swap(L,R) :- swapA(L,[],R).
swapA([],A,A).
swapA([H,H2|T],A,R) :-  swapA(T, append(A,[H2,H]), R).

Thanks.

2
Just an observation, no pun intended: One more Prolog code that was written like Erlang...user502187
@CookieMonster why like Erlang? why not like Haskell or C or Java or any functional or imperative language? I would say it's Erlang if he wrote foo(42); foo(X). but that's not the case...Thanos Tintinidis
Yes, it is not completely Erlang. But you are right, the main point is functonal use of predicates.user502187
@Daniel Sopel: Please correct your question: You want [B,A,D,C,F,E] not E,F and you got append(append(append([],[B,A]),[D,C]),[F,E])..false

2 Answers

8
votes

Several things:

  • a variable starts with a capital letter, if you want to differenciate an atom from a variable, wrap it between ': ['A','B','C','D','E','F']
  • you do not need append to successfully implement this predicate. The complexity is way worse when using append.
  • because you do not need append, you do not need 3 arguments either, 2 suffice

Here is a suggestion:

swapA([], []).
swapA([X, Y|T], [Y, X|R]) :- swapA(T, R).

And consider adding another base case if you want your predicate to hold when you have an odd number of elements in your list:

swapA([X], [X]).
3
votes

You can't call a Prolog predicate like a function. It doesn't return anything. When you pass append(A,[H2,H]) to swap, it interprets it as data, not as code.

A Prolog clause creates a relation between N logic variables. That means in theory there is no concept of "input" and "output" in Prolog predicates, you can make a query with any combination of instantiated and non-instantiated variables, and the language will find the meaningful relation(s) for you:

1 ?- append([a],[b,c],[a,b,c]).
true.

2 ?- append([a],[b,c],Z).
Z = [a, b, c].

3 ?- append([a],Y,[a,b,c]).
Y = [b, c].

4 ?- append(X,[b,c],[a,b,c]).
X = [a] ;
false.

5 ?- append([a],Y,Z).
Z = [a|Y].

6 ?- append(X,[b,c],Z).
X = [],
Z = [b, c] ;
X = [_G383],
Z = [_G383, b, c] ;
X = [_G383, _G389],
Z = [_G383, _G389, b, c] . % etc

7 ?- append(X,Y,[a,b,c]).
X = [],
Y = [a, b, c] ;
X = [a],
Y = [b, c] ;
X = [a, b],
Y = [c] ;
X = [a, b, c],
Y = [] ;
false.

8 ?- append(X,Y,Z).
X = [],
Y = Z ;
X = [_G362],
Z = [_G362|Y] ;
X = [_G362, _G368],
Z = [_G362, _G368|Y] . % etc

9 ?- 

In practice, not every predicate can be called with every combination, due to limitations in expressing the relation in a way that will not yield an infinite loop. Other cause may be extra-logic features, like arithmetic. When you see a predicate documented like:

pred(+Foo, -Bar, ?Baz)

That means it expects Foo to be instantiated (i.e. unified to another non-var), Bar to be a free variable and Baz can be anything. The same predicate can have more than one way to call it, too.

This is the reason you can't treat a Prolog relation as a function, in general. If you pass a compound as argument, the clauses will likely treat it just as a compound, unless it is specifically designed to handle it as code. One example is call/1, which executes its argument as code. is, =:=, < and other arithmetic operators do some interpretation too, in case you pass something like cos(X).