Related
Hie, I am a newbie in Prolog, especially recursion in Prolog. Here, start recursive on list X, makepairs recursive on list Y. These two rules should make a list of the pairs of items on X and Y. For example, if I enter query:
?- start([a,b], [c,d], Z)
Prolog should print out:
Z = [pair(a,c), pair(a,d), pair(b,c), pair(b,d)].
But my code prints only false. Could anyone help to find the bug in my code?
start([H|T], Y, Z):- makepairs(H, Y, Z), start(T, Y, Z).
start([], _Y, []).
makepairs(X, [H|T], Z) :- append([pair(X,H)], [], Z), makepairs(X, T, Z).
makepairs(_X, [], _Z).
Using library(lamdba) preinstalled in Scryer, available for
SICStus|SWI.
start(Xs, Ys, XYs) :-
maplist(\X^Y^pair(X,Y)^true, Xs, Ys, XYs).
Or manually,
list_list_pairs([], [], []).
list_list_pairs([X|Xs], [Y|Ys], [pair(X,Y)|Pairs]) :-
list_list_pairs(Xs, Ys, Pairs).
Note that this not only constructs such pairs, but it can also be used to "unzip" them:
?- list_list_pairs(Xs, Ys, [pair(1,one), pair(2,two), pair(3,three)]).
Xs = [1,2,3], Ys = [one,two,three].
But, maybe I should add, using pair/2 as a functor is fairly uncommon. It is more idiomatic in Prolog to use (-)/2 instead, which is so much more compact, think of
Ps = [1-one,2-two,3-three].
% vs
Ps = [pair(1,one), pair(2,two), pair(3,three)]
Assuming that this is a learning exercise, you are supposed to roll your own...
For the purposes of this exercise, I'm going to elect to represent the tuple using the :/2 operator (x:y), simply because it's less typing, more compact, and and easier on the eyes than, say, [x,y].
So, there are 3 cases in this problem:
Both lists are the empty list. The result is the empty list. You can represent that as
zip( [] , [] , [] ) .
Both lists are non-empty lists. The result is that we prepend the pair to the result list, and continue, thus:
zip( [X|Xs] , [Y|Ys] , [X:Y|Zs] ) :- zip(Xs,Ys,Zs) .
And then, there is the case where one list is empty and the other is non-empty. You need to consider how to handle that situation. You could
Fail.
Terminate the program and succeed, discarding the unmatched items.
Include the unpaired item as itself.
Include the unpaired item in the same x:y pair structure, selecting some atom to represent the missing data.
Here, I choose to include the last option, and will represent the missing data with the atom nil, so [nil:y] or [x:nil].
You can represent this in Prolog as
zip( [] , [Y|Ys] , [nil:Y|Zs] ) :- zip([],Ys,Zs) .
zip( [X|Xs] , [] , [X:nil|Zs] ) :- zip(Xs,[],Zs) .
Putting it all together, you get this:
zip( [] , [] , [] ) .
zip( [] , [Y|Ys] , [nil:Y|Zs] ) :- zip([],Ys,Zs) .
zip( [X|Xs] , [] , [X:nil|Zs] ) :- zip(Xs,[],Zs) .
zip( [X|Xs] , [Y|Ys] , [X:Y|Zs] ) :- zip(Xs,Ys,Zs) .
which you can fiddle with at https://swish.swi-prolog.org/p/zip/unzip.pl
Running
zip( [a,b,c], [1,2,3], Ps ).
results in
P = [ a:1, b:2, c:3 ]
You might note that this will also unzip a list of tuples, so running
zip(Xs,Ys,[a:1,b:2,c:3]).
results in
Xs = [a,b,c]
Ys = [1,2,3]
This line cannot succeed:
start([H|T],Y,Z):- makepairs(H,Y,Z), start(T,Y,Z).
The first part requires Prolog to find a value for Z which is the list of all pairs, the second part requires Z to become only the list of H paired with every element in Y, and the third part requires Z to become the pairs of the tail and Y.
One single Z cannot be three different things at the same time, the predicate cannot hold, and false must be the result.
This line:
start([],_Y,[]).
Introduces a helper variable, which you never use.
This line:
makepairs(X,[H|T],Z):-append([pair(X,H)],[], Z), makepairs(X,T,Z).
requires that Z is the list of pairs of X with everything in [H|T], and also that Z is what you get when you append an empty list onto a list with one pair, and that Z is the list of pairs of X with T. This has the same problem of requiring Z to be three different things. These lines are where you need to introduce helper variables such as Z_.
Flaws in the predicate makepairs/3
In the base case, makepairs(_X, [], _Z), the variable _Z remains free, but it should be instantiated to [].
In the recursive case, append([pair(X, H), [], Z] is equivalent to Z = [pair(X, H)] (however, all you need is Z = pair(X,H)); also, the recursive call must produce a list containing the remaining pairs, say Zs. So the final result should be [Z|Zs].
Thus, a correct code is:
makepairs(_X, [], []).
makepairs(X, [H|T], [Z|Zs]):-
Z = pair(X,H),
makepairs(X, T, Zs).
Example:
?- makepairs(a, [c,d], Pairs).
Pairs = [pair(a, c), pair(a, d)] ;
false. % <= spurious choice point!
Flaws in predicate start/3
In the recursive case, subgoal makepairs(H, Y, Z) produces a list Z containing only pairs whose first elements are equal to H; then, the recursive call must produce a list Zs containing the remaining pairs. So, the final result, say Zss, must be the concatenation of lists Z and Zs.
Thus, a correct code is:
start([], _Y, []).
start([H|T], Y, Zss):-
makepairs(H, Y, Z),
append(Z, Zs, Zss),
start(T, Y, Zs).
Example:
?- start([a,b], [c,d], Z).
Z = [pair(a, c), pair(a, d), pair(b, c), pair(b, d)] ;
false. % <= spurious choice point
A BETTER SOLUTION
A better solution, that avoid spurious choice point using first argument indexing, is:
make_pairs([], _, []).
make_pairs([X|Xs], Y, Pairs):-
make_pairs_helper(Y, X, Px),
append(Px, Pxs, Pairs),
make_pairs(Xs, Y, Pxs).
make_pairs_helper([], _, []).
make_pairs_helper([Y|Ys], X, [pair(X,Y)|Zs]):-
make_pairs_helper(Ys, X, Zs).
Example:
?- make_pairs([a,b], [c,d], Pairs).
Pairs = [pair(a, c), pair(a, d), pair(b, c), pair(b, d)].
Remark It's more idiomatic to use - as separator of the elements of a pair in Prolog.
I am having trouble understanding prolog, I have to find if X is before Y in a list.
so I have a base case with an empty list
before(X, Y, [ ]).
Now I know that I want to check the index of X and the index of Y in List and if indexX < indexY I want to have a success.
Could someone explain a simple way to do this?
You can use append/3 to locate X and the remaining list after it, then locate Y.
before(X, Y, L):-
append(_, [X|Tail], L),
append(_, [Y|_], Tail).
Using a DCG, it would look like this (using a predicate named ... for notational/visual convenience):
before(X, Y) --> ..., [X], ..., [Y], ... .
... --> [].
... --> [_], ... .
| ?- phrase(before(X, Y), [a,b,c]).
X = a
Y = b ? ;
X = a
Y = c ? ;
X = b
Y = c ? ;
(1 ms) no
And you can wrap it in a predicate, if you wish:
before(X, Y, L) :- phrase(before(X, Y), L).
As #CapelliC points out, the above predicate succeeds if there is at least one case in the list in which X comes before Y. However, if the definition is, X is seen before Y in the list, then an alternative DCG implementation could be:
before(X, Y) --> anything_but(Y), [X], ..., [Y], ... .
anything_but(_) --> [].
anything_but(Y) --> [X], { dif(X, Y) }, anything_but(Y).
... --> [].
... --> [_], ... .
Which results in:
| ?- phrase(before(X,Y), [b,a,b]).
X = b
Y = b ? a
X = a
Y = b
no
In Prolog, list processing is in most cases done without using indices: you use recursion, and you try to formulate it as a logical expression. If you don't want to use built-ins, you can write:
before(X,Y,[X|T]) :-
!,
contains(Y,T).
before(X,Y,[_|T]) :-
before(X,Y,T).
contains(Y,[Y|_]) :-
!.
contains(Y,[_|T]) :-
contains(Y,T).
The code makes use of a defined contains/2 predicate that checks whether the list L contains Y. Now the before/2 predicate contains two clauses. The first clause specifies that the first element of the list is X, in that case, we only need to check whether the remainder of the list contains an Y. In case the first element of the list is not an X, the list is shifted one further, and by using recursion, we try to find a location where there is an X.
Note that this predicate requires that both X and Y are elements of the list. Furthermore there can be multiple X and Ys. So before(a,b,[b,a,a,b]) will succeed, simple because there is an a and a b such that the a is before the b.
EDIT
If you want to use the predicate in a reversed way (query fashion), you should omit the cuts:
before(X,Y,[X|T]) :-
contains(Y,T).
before(X,Y,[_|T]) :-
before(X,Y,T).
contains(Y,[Y|_]).
contains(Y,[_|T]) :-
contains(Y,T).
Then you can query like:
?- before(X,Y,[a,b,c]).
X = a,
Y = b ;
X = a,
Y = c ;
X = b,
Y = c ;
false.
Here's a simple solution that uses no built-in predicates whatsoever.
It helps if you re-cast the problem in somewhat more generic terms.
A common prolog idiom is a public predicate that invokes a worker predicate that does all the work. Often, the worker predicate will carry additional variable that maintain state. In this case, we don't need to maintain state, but it simplifies things if we make the actual solution more generic: instead of defining the problem in terms of X and Y, redefineit in terms of a list of arbitrary length, defining the order in which things must be found in the target list.
Then, it's simply a matter of recursing down both lists in parallel to determine if the precedence constraints are satisfied. The generic solution (which will work for a list containing an arbitrary number of constraints) has 3 cases:
The constraint list is empty: Success!
The head of the constraint list unifies with the head of the list being
tested. That indicates that a constraint has been satisfied. Remove both the
constraint and the item it just matched (the head of the list being tested)
and recurse down.
Finally, just remove the head of the list being tested and recurse down.
The solution looks like this:
x_before_y( X , Y, Zs ) :- satisfies_constraints( [X,Y] , Zs ) .
satisfies_constraints( [] , _ ) .
satisfies_constraints( [C|Cs] , [C|Xs] ) :- satisfies_constraints(Cs,Xs) .
satisfies_constraints( Cs , [_|Xs] ) :- satisfies_constraints(Cs,Xs) .
On backtracking, this will find all possible solutions. If that's not desirable, a cut in the 2nd clause will eliminate the choice points:
satisfies_constraints( [] , _ ) .
satisfies_constraints( [C|Cs] , [C|Xs] ) :- !, satisfies_constraints(Cs,Xs) .
satisfies_constraints( Cs , [_|Xs] ) :- satisfies_constraints(Cs,Xs) .
As will introducing a test for non-unifiability in the 3rd clause:
satisfies_constraints( [] , _ ) .
satisfies_constraints( [C|Cs] , [C|Xs] ) :- satisfies_constraints(Cs,Xs) .
satisfies_constraints( [C|Cs] , [X|Xs] ) :-
C \= X ,
satisfies_constraints([C|Cs],Xs)
.
I'm trying to compare the elements of a list of integer to see if they are ordered (or not). I'm using Amzi!
I gave a few attempts, but nothing works... :(
ordered([X]).
ordered([N|[N1|L]]) :- N <= N1, ordered([N1|L]).
ordered_([X]).
ordered_([Head,Head1|Tail]) :- Head <= Head1, ordered_([Head1|Tail]).
Both return no if this list is entered:
ordered([1,2,3,4]).
ordered_([1,2,3,4]).
I understand that I need to compare the head with the head of the tail.
Doesn't seem like it should be any more complex than
ordered( [] ) .
ordered( [_] ) .
ordered( [X,Y|Z] ) :- X =< Y , ordered( [Y|Z] ) .
Arithmetic comparison predicates are covered here: http://www.amzi.com/manuals/amzi/pro/ref_math.htm#MathematicalComparisons
Use #=</2 or compare/3 to check the ordering of things in the standard order of terms: http://www.amzi.com/manuals/amzi/pro/ref_manipulating_terms.htm#StandardOrder
a compact alternative:
ordered(L) :- \+ ( append(_,[A,B|_], L), A > B ).
More efficient alternative to most upvoted solution, comparing three instead of appending the bigger element back to the list
is_sorted([]).
is_sorted([X, Y, Z|T]) :- X =< Y, Y =< Z, is_sorted(T).
is_sorted([X, Y|T]) :- X =< Y, is_sorted(T).
How can I replace a list with another list that contain the variable to be replaced. for example
rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p]
the x to z and z doesn't change after it has been replaced.
so far I did only the one without the list
rep([], _, []).
rep(L1, H1=H2, L2) :-
rep(L1, H1, H2, L2).
rep([],_,_,[]).
rep([H|T], X1, X2, [X2|L]) :-
H=X1,
rep(T,X1,X2,L),
!.
rep([H|T],X1,X2,[H|L]) :-
rep(T,X1,X2,L).
If you use SWI-Prolog, with module lambda.pl found there : http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl you can write :
:- use_module(library(lambda)).
rep(L, Rep, New_L) :-
maplist(\X^Y^(member(X=Z, Rep)
-> Y = Z
; Y = X), L, New_L).
You should attempt to keep the code simpler than possible:
rep([], _, []).
rep([X|Xs], Vs, [Y|Ys]) :-
( memberchk(X=V, Vs) -> Y = V ; Y = X ),
rep(Xs, Vs, Ys).
Of course, note the idiomatic way (thru memberchk/2) to check for a variable value.
Still yet a more idiomatic way to do: transforming lists it's a basic building block in several languages, and Prolog is no exception:
rep(Xs, Vs, Ys) :- maplist(repv(Vs), Xs, Ys).
repv(Vs, X, Y) :- memberchk(X=V, Vs) -> Y = V ; Y = X .
Here's how you could proceed using if_/3 and (=)/3.
First, we try to find a single Key in a list of pairs K-V.
An extra argument reifies search success.
pairs_key_firstvalue_t([] ,_ ,_ ,false).
pairs_key_firstvalue_t([K-V|KVs],Key,Value,Truth) :-
if_(K=Key,
(V=Value, Truth=true),
pairs_key_firstvalue_t(KVs,Key,Value,Truth)).
Next, we need to handle "not found" cases:
assoc_key_mapped(Assoc,Key,Value) :-
if_(pairs_key_firstvalue_t(Assoc,Key,Value),
true,
Key=Value).
Last, we put it all together using the meta-predicate maplist/3:
?- maplist(assoc_key_mapped([x-z,z-x,d-c]), [x,d,e,z,a,z,p], Rs).
Rs = [z,c,e,x,a,x,p]. % OK, succeeds deterministically
Let's improve this answer by moving the "recursive part" into meta-predicate find_first_in_t/4:
:- meta_predicate find_first_in_t(2,?,?,?).
find_first_in_t(P_2,X,Xs,Truth) :-
list_first_suchthat_t(Xs,X,P_2,Truth).
list_first_suchthat_t([] ,_, _ ,false).
list_first_suchthat_t([E|Es],X,P_2,Truth) :-
if_(call(P_2,E),
(E=X,Truth=true),
list_first_suchthat_t(Es,X,P_2,Truth)).
To fill in the "missing bits and pieces", we define key_pair_t/3:
key_pair_t(Key,K-_,Truth) :-
=(Key,K,Truth).
Based on find_first_in_t/4 and key_pair_t/3, we can write assoc_key_mapped/3 like this:
assoc_key_mapped(Assoc,Key,Value) :-
if_(find_first_in_t(key_pair_t(Key),_-Value,Assoc),
true,
Key=Value).
So, does the OP's use-case still work?
?- maplist(assoc_key_mapped([x-z,z-x,d-c]), [x,d,e,z,a,z,p], Rs).
Rs = [z,c,e,x,a,x,p]. % OK. same result as before
Building on find_first_in_t/4
memberd_t(X,Xs,Truth) :- % memberd_t/3
find_first_in_t(=(X),_,Xs,Truth).
:- meta_predicate exists_in_t(2,?,?). % exists_in_t/3
exists_in_t(P_2,Xs,Truth) :-
find_first_in_t(P_2,_,Xs,Truth).
I find your code rather confused. For one thing, you have rep/3 and rep/4, but none of them have a list in the second position where you're passing the list of variable bindings. H1=H2 cannot possibly match a list, and that's the only rep/3 clause that examines the second argument. If this is a class assignment, it looks like you're a little bit behind and I'd suggest you spend some time on the previous material.
The solution is simpler than you'd think:
rep([], _, []).
rep([X|Xs], Vars, [Y|Rest]) :- member(X=Y, Vars), rep(Xs, Vars, Rest).
rep([X|Xs], Vars, [X|Rest]) :- \+ member(X=_, Vars), rep(Xs, Vars, Rest).
We're using member/2 to find a "variable binding" in the list (in quotes because these are atoms and not true Prolog variables). If it's in the list, Y is the replacement, otherwise we keep using X. And you see this has the desired effect:
?- rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p] ;
false.
This could be made somewhat more efficient using "or" directly (and save us a choice point):
rep([], _, []).
rep([X|Xs], Vars, [Y|Ys]) :-
(member(X=Y, Vars), ! ; X=Y),
rep(Xs, Vars, Ys).
See:
?- rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p].
Okay, my last prolog question. It's the common geneaology problem.
I am suppose to take a list of facts and have a function called descendant that
will return a list that has all the descendants. For example:
Given the rules:
parent('Bob', 'Tim').
parent('Joe', 'Bob').
The function call:
descendant('Joe', X).
should return:
X = ['Bob', 'Tim'].
I can get it to return the immediate descendant of 'Joe' but not the full line. Here's what I have.
% Recursive case
descendant(X,DList) :- parent(X,A), NewDList = [A|DList],
descendant(A, NewDList).
% Base case, I have a feeling this is wrong.
descendant(_,[]).
This code only seems to return true or false, or just an empty [].
I could use some help on what I might need to look at. Thanks.
Firstly, we'll create a predicate that can finds a single descendant.
descendant(X, Y) :- parent(X, Y).
descendant(X, Y) :- parent(X, Z), descendant(Z, Y).
We can then use the findall predicate to list all descendants:
descendants(X, L) :- findall(A, descendant(X, A), L).
So, for instance:
parent(bob, tim).
parent(joe, bob).
parent(joe, mary).
descendant(X, Y) :- parent(X, Y).
descendant(X, Y) :- parent(X, Z), descendant(Z, Y).
descendants(X, L) :- findall(A, descendant(X, A), L).
gives:
?- descendants(joe, X).
X = [bob, mary, tim].
My Prolog is a bit rusty and I'm loathe to post an answer to such a problem - you won't learn much that way.
I'll just point out that you shouldn't have that assignment statement in there - NewDList = [A|DList] - this is considered bad form in the Prolog style of programming - assignments should only be used where there is not a "pure" logical solution - certainly not the case here.
Cheers,
Craig.
parent('Bob', 'Tim').
parent('Joe', 'Bob').
descendant(X,[H|T]) :- parent(X,H), descendant(H, T).
descendant(X,[]) .
returns
?- descendant('Joe', L).
L = ['Bob', 'Tim'] ;
L = ['Bob'] ;
L = [].
actually it is hard to write predicate that will return only ['Bob', 'Tim'] because list ['Bob'] is also valid. if you decide to leave only longest chain it gets too comlicated
if i understood question incorrectly here is one version:
desc(X, A) :- parent(X,H), desc(H, A).
desc(X, A) :- X = A.