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.
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]).
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).
Related
The following Prolog program defines a predicate deleted/3 for deleting all the occurrences of the item passed in first argument from the list passed in second argument and results in the list passed in third argument:
deleted(_, [], []).
deleted(X, [X|Y], Z) :-
deleted(X, Y, Z).
deleted(U, [V|W], [V|X]) :-
deleted(U, W, X),
U \= V.
It works with queries in this argument mode:
?- deleted(a, [a, b, a], [b]).
true
; false.
It also works with queries in this argument mode:
?- deleted(X, [a, b, a], [b]).
X = a
; false.
It also works with queries in this argument mode:
?- deleted(a, [a, b, a], Z).
Z = [b]
; false.
It also works with queries in this argument mode:
?- deleted(X, [a, b, a], Z).
X = a, Z = [b]
; X = b, Z = [a, a]
; false.
It also works with queries in this argument mode:
?- deleted(a, Y, Z).
Y = Z, Z = []
; Y = [a], Z = []
; Y = [a, a], Z = []
; Y = [a, a, a], Z = []
; Y = [a, a, a, a], Z = []
; …
It also works with queries in this argument mode:
?- deleted(X, Y, Z).
Y = Z, Z = []
; Y = [X], Z = []
; Y = [X, X], Z = []
; Y = [X, X, X], Z = []
; Y = [X, X, X, X], Z = []
; …
But it exhausts resources with queries in this argument mode:
?- deleted(a, Y, [b]).
Stack limit (0.2Gb) exceeded
Stack sizes: local: 0.2Gb, global: 28.1Mb, trail: 9.3Mb
Stack depth: 1,225,203, last-call: 0%, Choice points: 1,225,183
Possible non-terminating recursion:
[1,225,203] deleted(a, _1542, [length:1])
[1,225,202] deleted(a, [length:1|_1584], [length:1])
It also exhausts resources with queries in this argument mode:
?- deleted(X, Y, [b]).
Stack limit (0.2Gb) exceeded
Stack sizes: local: 0.2Gb, global: 28.1Mb, trail: 9.3Mb
Stack depth: 1,225,179, last-call: 0%, Choice points: 1,225,159
Possible non-terminating recursion:
[1,225,179] deleted(_1562, _1564, [length:1])
[1,225,178] deleted(_1596, [length:1|_1606], [length:1])
How to implement list item deletion for all argument modes?
Intro
Pure Prolog conjunctions and disjunctions are, in fact, commutative and associative.
This allows us to ignore clause and goal order, provided that all answer sequences are finite.
When queries have infinite solution sets, Prolog may need to systematically enumerate infinite answer sequences.
The fix
To help Prolog find answers for above “problematic” queries, swap the two recursive rules:
deleted(_,[],[]).
deleted(U,[V|W],[V|X]) :- % this clause was last
dif(U,V),
deleted(U,W,X).
deleted(X,[X|Y],Z) :-
deleted(X,Y,Z).
Demo
Let’s run your queries again with above code changes!
The finite ones work like before1:
?- deleted(a,[a,b,a],[b]). % Q1
true
; false.
?- deleted(X,[a,b,a],[b]). % Q2
X = a
; false.
?- deleted(a,[a,b,a],Z). % Q3
Z = [b]
; false.
?- deleted(X,[a,b,a],Z). % Q4
Z = [a,b,a], dif(X,a), dif(X,b)
; Z = [a, a], X=b
; Z = [ b ], X=a
; false.
Some infinite ones were okay before—they still are:
?- deleted(a,Y,Z). % Q5
Y = Z, Z = []
; Y = Z, Z = [_A], dif(_A,a)
; Y = Z, Z = [_A,_B], dif(_A,a), dif(_B,a)
; Y = Z, Z = [_A,_B,_C], dif(_A,a), dif(_B,a), dif(_C,a)
; …
?- deleted(X,Y,Z). % Q6
Y = Z, Z = []
; Y = Z, Z = [_A], dif(X,_A)
; Y = Z, Z = [_A,_B], dif(X,_A), dif(X,_B)
; Y = Z, Z = [_A,_B,_C], dif(X,_A), dif(X,_B), dif(X,_C)
; …
Some infinite ones used to be “problematic”—not anymore:
?- deleted(a,Y,[b]). % Q7
Y = [b]
; Y = [b,a]
; Y = [b,a,a]
; Y = [b,a,a,a]
; …
?- deleted(X,Y,[b]). % Q8
Y = [b], dif(X,b)
; Y = [b,X], dif(X,b)
; Y = [b,X,X], dif(X,b)
; Y = [b,X,X,X], dif(X,b)
; Y = [b,X,X,X,X], dif(X,b)
; …
Analysis
Now, ?- deleted(X,Y,[b]). makes Prolog give us answers.
But why did we run out-of-memory?
How come it did not work?
To explain this, let’s take a step back: the default / vanilla / out-of-the-box prolog-toplevel of many2 Prolog systems initially runs each query until it discovers either (0) finite failure or (1) the 1st answer3.
Before the fix, we observed neither. Why not?
Why no finite failure?
deleted(a,[a,b,a],[b]) holds true.
Therefore, the more general deleted(X,Y,[b]) must not fail.
Why no (1st) answer?
Prolog proceeds depth-first, top-down, left-to-right.
So when …
?- deleted(X,Y,[b]).
… “meets” …
deleted(X,[X|Y],Z) :-
deleted(X,Y,Z).
… inside the Prolog machine, the following happens:
A choicepoint is created for saving the information—to be used upon backtracking—that another clause could have been selected.
Next, Prolog proceeds with a recursive goal which is just like the original one: we are no closer to an answer, as the 3rd argument—the only instantiated one—stays exactly the same.
Eventually, this loop runs out of memory—which is exactly the behavior that you observed.
If we swap two recursive clauses, the following clause becomes our top-most recursive clause:
deleted(U,[V|W],[V|X]) :-
dif(U,V),
deleted(U,W,X).
Now, something is going on with the 3rd argument: Prolog recursively walks down the single-linked list until [] (or a free logical variable) is reached. Only then can Prolog make use of the fact deleted(_,[],[]). and give us an answer.
Footnotes:
In fact better, as we preserve logical-purity by using dif/2 for expressing syntactic term inequality.
More on dif/2: prolog-dif
All command-line-interface based Prolog systems I have ever used.
Not stopping at the 1st answer is way better for code quality—particularly in regard to universal termination properties.
GUPU, an excellent environment specialized for Prolog and constraint programming courses, does the right thing—by default!
“Answer substitutions are displayed in chunks of five.”
Given atom x, I am trying to split a list into one with atoms smaller than x and one with atoms equal to or greater than x.
For example)
%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) should give me
%% AtomSmall = [a,b,c], AtomBig = [d,e,f]
Below is what I've tried so far. I get the concept.However my code includes the atom that is equivalent to x in AtomSmall list, not AtomBig, although I check the case with before predicate.
For example)
%% split(d,[a,b,c,d,e,f],AtomSmall, AtomBig) gives me
%% AtomSmall = [a,b,c,d], AtomBig = [e,f]
before(X,Y):-atom_codes(X,A),atom_codes(Y,B),small(A,B).
small([],[]).
small([H1|T1],[H2|T2]):-H1<H2.
small([H1|T1],[H2|T2]):-H1=:=H2,small(T1,T2).
split(X,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-before(H1,X),split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):-not(before(H1,X)),split(X,T1,Small,Big).
Please help!
In SWI-Prolog, you can use partition/4 from library(lists) and the standard order comparison (#>)/2:
?- lists:partition(#>(d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].
Since the order of arguments in comparison is fixed passing the pivot in as first argument, a lambda expression (using library(yall), needs a recent version) can help to give a more intuitive reading:
?- partition([E]>>(E#<d),[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f].
Anyway, your code could be patched like this:
split(_,[],[],[]).
split(X,[H1|T1],[H1|Small],Big):-H1#<X,split(X,T1,Small,Big).
split(X,[H1|T1],Small,[H1|Big]):- \+ H1#<X,split(X,T1,Small,Big).
?- split(d,[a,b,c,d,e,f],L,R).
L = [a, b, c],
R = [d, e, f] ;
false.
Your before/2 predicate succeeds if the arguments are lexicographically equivalent. For example, before(a, a) is true. That's because your 3rd clause allows equal values throughout the list until the base case finally succeeds with two empty lists.
In addition, something you haven't encountered yet evidently, is that before(X, Y) will fail if X and Y are different length atoms. For example, before(ab, abc) will fail. So your small/2 needs to take care of that case as well.
A refactoring of small/2 will fix that:
% 1st clause is fixed so unequal length atoms are handled properly
small([], _).
small([H1|_], [H2|_]) :- H1 < H2.
% 3rd clause is fixed so that equal atoms won't succeed here
small([H,H1|T1], [H,H2|T2]) :- small([H1|T1], [H2|T2]).
But... you don't need to go through all that with before/2. Prolog knows how to compare, in a sensible way, atoms (and general Prolog terms) using the #< and #> operators, as #CapelliC indicated in his answer. So your before/2 just becomes:
before(X, Y) :- X #< Y.
And you don't need small/2 at all. That's basically the second solution that #CapelliC showed in his answer.
I want to create two Prolog relations and place their definitions in a single Prolog file. Define the relations prefix and postfix on lists, meaning that the first argument is a prefix or postfix, respectively, of the second.
?- consult(prepost).
% prepost compiled 0.00 sec, 956 bytes
true.
?- prefix([a,b,c],[a,b,c,e,f]).
true.
?- prefix([a,b,c], [a,b,e,f]).
false.
?- prefix([a,b],[a]).
false.
?- prefix([],[a,b,c,d]).
true.
?- prefix(X,[a,b,c,d]).
X = [] ;
X = [a] ;
X = [a, b] ;
X = [a, b, c] ;
X = [a, b, c, d] ;
false.
?- postfix([n,e],[d,o,n,e]).
true .
?- postfix([],[a,n,y,t,h,i,n,g]).
true .
?- postfix([a,b,c],[a,b,c,d,e]).
false.
?- postfix(X,[a,b,c,d]).
X = [a, b, c, d] ;
X = [b, c, d] ;
X = [c, d] ;
X = [d] ;
X = [] ;
false.
?-
You can use the predicate append/3 to solve your problem in a simple way.
A list of elements is prefix of some other list, if there is a combination where this first list concatenated with another (not relevant), results in your full list.
prefix(Prefix_list, Full_list):- append(Prefix_list, _, Full_list).
You can infer your predicate postfix/2 in the same way:
postfix(Postfix_list, Full_list):- append(_, Postfix_list, Full_list).
Now, put both predicate in a text file, name it prepost.pl, and that's it.
I'm working on my homework for Prolog (SWI) but can't figure out how to get this done:
I have the functor:
palindrome([]).
palindrome([_]).
palindrome([A|T]) :-
append(Middle,[A],T),
palindrome(Middle).
which tells if a given list is a palindrome.
For my homework I have to write a functor palindrome/2 without append/3 and with difference lists.
I know a difference list is a form of [Y|X]-X, but I don't understand how to use this and how this can replace the append functor.
Can somebody please explain this to me?
For a given list of length n, your solution needs some O(n2) inferences: n (actually n/2) for palindrome/1 and i for each append/3 which simply searches and compares the end.
The most straight forward way to reformulate your definition uses grammars (DCGs) that are a convenient way to use difference-lists. Note that each grammar rule corresponds to a clause in your program.
palindrome -->
[].
palindrome -->
[_].
palindrome -->
[A],
palindrome,
[A].
palindrome(T) :-
phrase(palindrome,T).
For convenience, here is the same grammar written more compactly:
palindrome --> [] | [_] | [A], palindrome, [A].
Now, how are these grammar rules implemented? The easiest way is to look at the actual definition with listing(palindrome).
?- listing(palindrome).
palindrome(A, A).
palindrome([_|A], A).
palindrome([C|A], D) :-
palindrome(A, B),
B=[C|D].
So this is now your definition using difference-lists.
Just write it down yourself. You have
palindrome([]). % palindrome(Z-Z).
palindrome([_]). % palindrome([_|Z]-Z).
palindrome([A|T]) :- % palindrome([A|T]-Z):-
append(Middle,[A],T), % append(Middle-Z2,[A|Z3]-Z3,T-Z),
palindrome(Middle). % palindrome(Middle-Z2).
Append for dif-lists is append(A-B,B-C,A-C), so the append call gives us Z2=[A|Z3], Z3=Z, Middle=T, and so (writing out the two halves of a dif-list as two arguments for the predicate),
palindrome(Z,Z).
palindrome([_|Z],Z).
palindrome([A|T],Z) :-
palindrome(T, [A|Z]).
Now you can run it
10 ?- palindrome(X,[]).
X = [] ;
X = [_G340] ;
X = [_G340, _G340] ;
X = [_G340, _G346, _G340] ;
X = [_G340, _G346, _G346, _G340] ;
....
11 ?- X=[a,b,c|_],palindrome(X,[z]).
X = [a, b, c, b, a, z] ;
X = [a, b, c, c, b, a, z] ;
X = [a, b, c, _G460, c, b, a, z] ;
X = [a, b, c, _G460, _G460, c, b, a, z] ;
....
16 ?- palindrome([1,2,2,1,0],Z).
Z = [1, 2, 2, 1, 0] ;
Z = [2, 2, 1, 0] ;
Z = [0] ;
No
Of course, DCG rules provide a comfortable interface to difference-lists.
I am new to prolog and i want to solve this problem. Suppose I have a list say
List i.e. [a,b,c]
now i have some facts say
likes(a,banana).
likes(b,orange).
likes(c,apple).
likes(d,grapes).
So if I make a query
?- my_functor(List,X).
X=[banana,orange,apple].
Thanks you.
Consider:
?- List=[a,b,c], findall(X, (member(Y, List), likes(Y, X)), Xs).
List = [a, b, c],
Xs = [banana, orange, apple].
Explanation:
findall/3 is called an 'all-solutions' predicate which seeks to find all possible values unifiable to the first argument (here, that's the variable X) to solutions for the seconds argument (here, that's the conjunction (member(Y, List), likes(Y, X))), and places all values for X into a list, bound to the third argument (here, that's Xs).
Notice that the inner expression generating the values for X is a statement that backtracks to provide different assignments for X:
?- member(Y, [a,b,c]), likes(Y, X).
Y = a,
X = banana ;
Y = b,
X = orange ;
Y = c,
X = apple ;
false.
Tested with SWI-Prolog.
Note that findall/3 also appears in GNU Prolog amongst most other implementations.