Prolog unification process (concat) - prolog

The following code works, but I have certain doubts as to how it does things under the hood. For example, on the first call to Exit(9) I don't understand how c is moved to the variable O. Is this part of the unification process or something else entirely? Care anyone to explain?
concat([], List, List).
concat([Head|[]], List, [Head|List]).
concat([Head|Tail], List, Concat) :- concat(Tail, List, C), concat([Head], C, Concat).

You can do 'by hand' the unification process, to verify that the trace line labelled Exit:(9) actually 'cons-ed' [c] to [x,y,z]:
?- [Head|[]]=[c],List=[x,y,z],[Head|List]=O.
Head = c,
List = [x, y, z],
O = [c, x, y, z].
but, you cannot claim it works:
?- concat([a,b,c],[x,y,z],L).
L = [a, b, c, x, y, z] ;
L = [a, b, c, x, y, z] ;
...
it doesn't terminate, and this clearly indicate some problem. The second clause is redundant - both in behaviour and syntax. It would be usually written like
concat([Head], List, [Head|List]).
since the empty tail list it's implicitly present in every list - except where a tail is explicitly indicated:
?- [Head|[]]=[X].
Head = X.
About the behaviour, you can see from your trace that it's the first clause that is never used. So, you can think it's the first that is redundant - maybe you added the second because of the last call of the third clause, where a 'singleton' list is required (I mean ...,concat([Head], C, Concat).). But such call it's causing the non termination issue. Better to simplify the whole program, removing the second clause and simplifying the third....

Related

SWI Prolog list subtract gives error: Out of local stack

I'm running some Prolog rule which uses the subtract function and in the stack trace, I found the source of error to be this:
lists:subtract([b, d | _], [b, d] , [r]) ? creep
ERROR: Out of local stack
The original call was:
member(b, X), member(d, X), subtract(X, [b, d], [r]).
and the expected output is [b, d, r].
I'm new to Prolog and unable to understand the source of error and how to fix it. Please help.
unable to understand the source of error and how to fix it.
Just take your query and look at the first two goals alone:
?- member(b, X), member(d, X).
X = [b,d|_A]
; X = [b,_A,d|_B]
; X = [b,_A,_B,d|_C]
; X = [b,_A,_B,_C,d|_D]
; X = [b,_A,_B,_C,_D,d|_E]
; ... .
Just these two goals produce already infinitely many answers. So no matter what follows, your query will never terminate. By chance, you may happen to get a solution, but more often than not you will end in some loop.
So first of all you need to fix this somehow.
Then consider the meaning of subtract/3 in SWI:
?- subtract([b,d,r], [b,d], [r]).
true.
?- subtract([b,d,X], [b,d], [r]).
false. % ?? why not X = r?
From this alone you can see that subtract/3 is not a relation. So you cannot use it as a relation like, say, append/3.
To fix this and keep as close to your original query, use library(reif) and library(lambda):
?- S1=[b,d,X], S2 = [b,d], tpartition(S2+\E^memberd_t(E,S2),S1,_,[r]).
S1 = [b,d,r], X = r, S2 = [b,d].
From SWI Prolog manual :
The library(lists) contains a number of old predicates for manipulating sets represented as unordered lists, notably intersection/3, union/3, subset/2 and subtract/3. These predicates all use memberchk/2 to find equivalent elements. As a result these are not logical while unification can easily lead to dubious results.
You are having this problem because subtract isn't pure and needs it's first two Arguments to be instantiated hence the + sign in it's documentation .
subtract(+Set, +Delete, -Result)
you can instead use union/3
union(+Set1, +Set2, -Set3)
you can know more about other mode indicators in here.

Prolog reverse/2 list output format

I am a beginner in Prolog and I am stuck in a homework assignment. I have to build a predicate myReverse(XS,YS) where XS is the reverse list of YS. I have built some logic as follows:
myReverse([],[]).
myReverse([H],[H]).
myReverse([L|H],[H|T]) :- myReverse(L,T).
This kinda works, but the output is not quite what I want. Some examples:
myReverse(L,[]).
L = [] % ok, that's fine
myReverse(L,[a]).
L = [a] % still fine
myReverse(L,[a,b]).
L = [[b]|a] % expected [b,a]
myReverse(L,[a,b,c]).
L = [[[c]|b]|a] % expected [c,b,a]
...
Is there any way I can achieve the expected output without using a accumulator or third party implementations like append?
Edit: This question is NOT a duplicate of Reversing a List in Prolog because I do NOT want to use accumulator. Also, this question is much more about the output format of my given solution than the solution itself.
You've misunderstood the [H|T] notation, tracing through the example reverse(L, [a, b]) will reveal it.
The first unification:
rule: myReverse([L|H],[H|T]) :- myReverse(L,T).
unified: myReverse([L|a], [a|[b]]) :- myReverse(L, [b]).
At this point a is a single atom, not a list, the T in [H|T] needs to be a list for a list to be complete. [a, b, c] is syntactic sugar for .(a, .(b, .(c, []))).
Your second unification, and third unifications are:
second: myReverse([b], [b]).
going back: myReverse([[b]|a], [a|[b]]) :- myReverse([b], [b]).
which outputs as: myReverse([[b]|a], [a, b]).
Your output [[b]|a] is not a complete list because a was an atom, not a list, which is why it's not output as [[b], a].
To not use an accumulator you'll need to add elements to the list as you exit the recursion and go back through the stack frames, keeping in mind a when you're handling a list or an atom:
myReverse([], []). % base case
myReverse([Head|Tail], Reversed) :-
myReverse(Tail, TailReversed), % recursive call
add_to_tail(Head, TailReversed, Reversed). % Put Head onto the end
add_to_tail(X, [],[X]). % base case
add_to_tail(X, [H|T], [H|Out]) :-
add_to_tail(X, T, Out). % recursive call, work done on exit
It's more efficient to use an accumulator. Best of luck learning Prolog.

extending a list of lists by a single element

I am trying to solve the following question in ProLog. I am a beginner.
Define a predicate extend such that if Xss and Yss are lists of
lists then extend(X, Xss, Yss) holds if Yss can be obtained by adding the
element X to the end of every element in Xss, e.g
?- extend(g, [[e], [b, c, f], [k, h]], Yss).
Yss = [[e, g], [b, c, f, g], [k, h, g]]
I have attempted this with the following, but there is an error message :
extend(X, [], []).
extend(X, [[Firstxss,_] | Restxss], Yss) :-
Firstxss is [Firstxss,_|X],
Yss is [Yss | [Firstxss,_]],
Xss is Restxss,
extend(X, Xss, Yss).
I have input the following :
?- extend(g, [[e], [b, c, f], [k, h]], Yss).
and it returns :
false.
I think I have a valid input and I do not understand why it is returning as false.
Since you want to do the same thing with every element of the outer list, this is quite a beautiful task for maplist/3. You can use append/3 to extend a list by an additional element like so:
?- append([1,2],[element],Z).
Z = [1, 2, element].
However, you'll want to have append/3 with two lacking arguments in maplist/3, therefore it would be opportune to have the first argument appended to the second argument. To realize that, you could write an auxiliary predicate that calls append/3 with the first two arguments flipped, e.g:
flippedappend(X,Y,Z) :-
append(Y,X,Z).
Building on this, you could define the actual relation like so:
x_lists_extended(X,Xss,Yss) :-
maplist(flippedappend([X]),Xss,Yss).
Your example query yields the desired result:
?- x_lists_extended(g, [[e], [b, c, f], [k, h]], Yss).
Yss = [[e, g], [b, c, f, g], [k, h, g]].
Note that you can also use this predicate the other way around:
?- x_lists_extended(X, Xss, [[e, g], [b, c, f, g], [k, h, g]]).
X = g,
Xss = [[e], [b, c, f], [k, h]] ;
false.
First, you have a singleton variable X here:
extend(X, [], []).
It would be better to say extend(_, [], []) because you never refer to X again. It's important to understand why this is the case. In Prolog, all the action happens because of relationships the variables are in. If the variable only appears in one place, it's not participating in any relationships, so it should be replaced with _. (If you make such a change and the code appears to be nonsense, stop and study it, because it always means you have misunderstood something.)
Second, is/2 is for evaluating arithmetic expressions. There's no math going on in this: Firstxss is [Firstxss,_|X] so you have confused it with =. This is really a double whammy though, because = does not mean assign in Prolog, it means unify. So there is no real situation in Prolog where you are going to have X = X+1 or anything like that, which is exactly the kind of thing yo'ure doing here, trying to reuse a variable for different purposes.
What does Firstxss mean in this clause? It looks like it is the first item in a nested list in the second argument in the head: in other words, if you called extend(g, [[e], [b, c, f], [k, h]], Yss), then Firstxss = e. The value of Firstxss can never change. It can only be rebound in a recursive call. So when you immediately say Firstxss is [Firstxss,_|X], what Prolog sees is b = [b,_|<another var>]. This does not unify and your predicate fails at this point. Say it advanced, somehow. You make the same mistake on the next line with Yss.
It would help to think about your problem relationally. You have the wrong base case too. What is your base case? It's the case where you have reached the end of the list, and what should you do? Append X. So this is your base case:
extend(X, [], [X]).
Now think about what you want to do in the other cases: you have a head and a tail. How do you extend? You extend the tail, and your result is the head appended to the extended tail. Try and write this clause yourself, it is not that difficult!
Once you have that, the machinery for extending nested lists is simple: you test the head to see if it is a list. If it is, recur on the head as well as the tail! Like so:
extend(X, [Y|Ys], Result) :-
(is_list(Y) -> extend(X, Y, Y1) ; Y1 = Y),
... % use Y1 as Y in building the result

Prolog: lexicographic comparison and split a list

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.

Why prolog outputs a weird tree-like list?

In this Prolog code I intend to list the first N primes,
(...)
biggerPrime(N,P) :-
isPrime(N),
P is N,
!.
biggerPrime(N,P) :-
N1 = N+1,
biggerPrime(N1,P).
primeListAcc(0,A,R,R) :- !.
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[P|L],R).
And it works fine if I want the list ordered backwards:
?- primeList(5,L).
L = [11, 7, 5, 3, 2].
But if I change the last line of the code from [P|L] to [L|P] like this:
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[L|P],R).
I get:
?- primeList(5,L).
L = [[[[[[]|2]|3]|5]|7]|11].
What am I missing? This is driving me mad!
Recall that a list is either the empty list [] or a term with functor '.' and two arguments, whose second argument is a list. The syntax [P|Ps] is shorthand notation for the term '.'(P, Ps), which is a list if Ps is a list (as is the case in your example). The term '.'(Ps, P), on the other hand, which can also be written as [Ps|P] (as you are doing), is not a list if P is not a list. You can obtain a reverse list with reverse/2.
Great, so you've discovered the problem of adding elements to the end of a list. In Prolog, we can do it with
add(X,L,Z):- L=[X|Z].
wait, what? How to read this? We must know the calling convention here. We expect L and Z to come in as uninstantiated variables, and we arrange for L from now on to point to a newly created cons node with X at its head, and Z its tail. Z to be instantiated, possibly, in some future call.
IOW what we create here is an open-ended list, L = [X|Z] = [X, ...]:
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,Z,L) :- N > 0, % make it explicitly mutually-exclusive,
N1 is N-1, % do not rely on red cuts which are easily
biggerPrime(A,P), % invalidated if clauses are re-arranged!
A1 is P+1,
L = [P|R], % make L be a new, open-ended node, holding P
primeListAcc(N1,A1,Z,R). % R, the tail of L, to be instantiated further
primeListAcc(0,A,R,R). % keep the predicate's clauses together
We can see now that Z is not really needed here, as it carries the [] down the chain of recursive calls, unchanged. So we can re-write primeListAcc without the Z argument, so that its final clause will be
primeListAcc(0,A,R):- R=[].
Keeping Z around as uninstantiated variable allows for it to be later instantiated possibly with a non-empty list as well (of course, only once (unless backtracking occurs)). This forms the basis of "difference list" technique.
To answer your literal question - here, consider this interaction transcript:
1 ?- X=[a|b].
X = [a|b]
2 ?- X=[a|b], Y=[X|c].
X = [a|b]
Y = [[a|b]|c]
the [a|b] output is just how a cons node gets printed, when its tail (here, b) is not a list. Atoms, as numbers, are not lists.

Resources