I'm working through the exercises on Learn Prolog Now! and I'm stumped on the very last question. Given the following facts:
byCar(auckland,hamilton).
byCar(hamilton,raglan).
byCar(valmont,saarbruecken).
byCar(valmont,metz).
byTrain(metz,frankfurt).
byTrain(saarbruecken,frankfurt).
byTrain(metz,paris).
byTrain(saarbruecken,paris).
byPlane(frankfurt,bangkok).
byPlane(frankfurt,singapore).
byPlane(paris,losAngeles).
byPlane(bangkok,auckland).
byPlane(singapore,auckland).
byPlane(losAngeles,auckland).
Write a predicate travel/2 which determines whether it is possible to travel from one place to another by chaining together car, train,
and plane journeys. For example, your program should answer yes to the
query travel(valmont,raglan) .
So, by using travel/2 to query the above database, you can find out
that it is possible to go from Valmont to Raglan. If you are planning
such a voyage, that’s already something useful to know, but you would
probably prefer to have the precise route from Valmont to Raglan.
Write a predicate travel/3 which tells you which route to take when
travelling from one place to another. For example, the program should
respond X = go(valmont,metz,
go(metz,paris,
go(paris,losAngeles))) to the query travel(valmont,losAngeles,X) .
here's my go functors:
go(X).
go(X,Y).
Here's my travel/2 predicate:
travel(X,Y) :- byCar(X,Y).
travel(X,Y) :- byCar(X,Z), travel(Z,Y).
travel(X,Y) :- byTrain(X,Y).
travel(X,Y) :- byTrain(X,Z), travel(Z,Y).
travel(X,Y) :- byPlane(X,Y).
travel(X,Y) :- byPlane(X,Z), travel(Z,Y).
However, I'm having trouble with my travel/3 predicate:
travel(X,Y,G) :- byCar(X,Y), G = go(X, Y).
travel(X,Y,G) :- byCar(X,Z), travel(Z,Y,G).
travel(X,Y,G) :- byTrain(X,Y), G = go(X, Y).
travel(X,Y,G) :- byTrain(X,Z), travel(Z,Y,G).
travel(X,Y,G) :- byPlane(X,Y), G = go(X, Y).
travel(X,Y,G) :- byPlane(X,Z), travel(Z,Y,G).
When I run the predicate in the question, I get:
?- travel(valmont,losAngeles,X).
X = go(paris, losAngeles) .
But it's not an entire list like the question needs. I'm not really sure how to accomplish that; whether I need to rewrite my predicates or not. Any help you could offer to help me learn what I'm doing wrong is super appreciated!
Your are not changing G appropriately in the travel/3 predicate.
travel(X,Y, go(X, Y)) :- byCar(X,Y).
travel(X,Y, go(X, Y)) :- byTrain(X,Y).
travel(X,Y, go(X, Y)) :- byPlane(X,Y).
travel(X,Y, go(X, Z, G)) :- byCar(X,Z), travel(Z,Y, G).
travel(X,Y, go(X, Z, G)) :- byTrain(X,Z), travel(Z,Y, G).
travel(X,Y, go(X, Z, G)) :- byPlane(X,Z), travel(Z,Y, G).
You get:
| ?- travel(valmont, losAngeles, G).
G = go(valmont,saarbruecken,go(saarbruecken,paris,go(paris,losAngeles))) ? ;
G = go(valmont,metz,go(metz,paris,go(paris,losAngeles))) ? ;
no
As a bonus you can just embed the type of travel too:
travel_(X,Y, car(X, Y)) :- byCar(X,Y).
travel_(X,Y, train(X, Y)) :- byTrain(X,Y).
travel_(X,Y, plane(X, Y)) :- byPlane(X,Y).
travel_(X,Y, car(X, Z, G)) :- byCar(X,Z), travel_(Z,Y, G).
travel_(X,Y, train(X, Z, G)) :- byTrain(X,Z), travel_(Z,Y, G).
travel_(X,Y, plane(X, Z, G)) :- byPlane(X,Z), travel_(Z,Y, G).
Now you get:
| ?- travel_(valmont, losAngeles, G).
G = car(valmont,saarbruecken,train(saarbruecken,paris,plane(paris,losAngeles))) ? ;
G = car(valmont,metz,train(metz,paris,plane(paris,losAngeles))) ? ;
no
Related
I am new to prolog and still learning the language.
I can't understand why my code in Prolog is not working.
I am trying to make some kind of translator with lists.
Input: translate([strings to translate], [dictionary], [translation])
ex. translate([m,n], [(m,c), (m,d), (n,e), (c,f)], X)
Needed output: X=[c,d,e]
Actual output: False
contain(,[]).
contain(X,[X|]).
contain(X,[_|L]) :- contain(X,L).
contain_2(X, [(X, Y) | ], Y).
contain_2(X, [|T], Y) :-
contain_2(X, T, Y).
tr(XS, L, Y) :-
contain(Z, XS),
contain_2(Z, L, Y).
translate(M, N, R) :-
setof(Y, tr(M, N, Y), R).
My code no matter what returns False, but I can't find the reason. I tried debugging and it seems like it returns false before entering setof. I have used setof before, but maybe I'm missing something. I changed the structure different times, but this version seems to return the least amount of warnings.
Several lines look like they are missing _.
I think the main issue is that contain_2 has no base case for when the list of pairs is empty. It will get to contain_2(X, [], Y) find no predicate matching that and fail. e.g.
?- trace, contain_2([1,2], [(1,a),(2,b)], [a,b]).
Call:contain_2([1, 2],[(1,a), (2,b)],[a, b])
Call:contain_2([1, 2],[(2,b)],[a, b])
Call:contain_2([1, 2],[],[a, b])
Fail:contain_2([1, 2],[],[a, b])
You need:
contain_2(_, [], _).
contain_2(X, [(X, Y) | _], Y).
contain_2(X, [_|T], Y) :-
contain_2(X, T, Y).
I want remove all appearences of an element on a list, similar to this, but in my case, the list may have non-instantiated variables. For example:
delMember(z, [A,B,A,z], L).
L = [A, B, A];
false.
and
delMember(A, [A, B, A, z], L).
L = [B,z];
false.
I tried defining delMember as the following:
delMember(_, [], []).
delMember(X, [X|Xs], Y) :- delMember(X, Xs, Y).
delMember(X, [T|Xs], [T|Y]) :- X \== T, delMember(X, Xs, Y).
With this definition, the last result I get is correct but it's still trying to instantiate the variables before that.
?- delMember(A, [A,B,A,z], R).
A = B, B = z,
R = [] ;
A = B,
R = [z] ;
A = z,
R = [B] ;
R = [B, z] ;
any ideas???
If you look at your second predicate clause:
delMember(X, [X|Xs], Y) :- delMember(X, Xs, Y).
Unification is occurring with the X in the first and second arguments. This leads to the results you are observing when you do your query. You need to apply the same operator as you did in your third clause. So your complete predicate (with some slightly changed variable names to be more conventional) would look like:
delMember(_, [], []).
delMember(X, [X1|Xs], Ys) :- X == X1, delMember(X, Xs, Ys).
delMember(X, [X1|Xs], [X1|Ys]) :- X \== X1, delMember(X, Xs, Ys).
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.
I am completely new to Prolog and trying some exercises. One of them is:
Write a predicate set(InList,OutList)
which takes as input an arbitrary
list, and returns a list in which each
element of the input list appears only
once.
Here is my solution:
member(X,[X|_]).
member(X,[_|T]) :- member(X,T).
set([],[]).
set([H|T],[H|Out]) :-
not(member(H,T)),
set(T,Out).
set([H|T],Out) :-
member(H,T),
set(T,Out).
I'm not allowed to use any of built-in predicates (It would be better even do not use not/1). The problem is, that set/2 gives multiple same solutions. The more repetitions in the input list, the more solutions will result. What am I doing wrong? Thanks in advance.
You are getting multiple solutions due to Prolog's backtracking. Technically, each solution provided is correct, which is why it is being generated. If you want just one solution to be generated, you are going to have to stop backtracking at some point. This is what the Prolog cut is used for. You might find that reading up on that will help you with this problem.
Update: Right. Your member() predicate is evaluating as true in several different ways if the first variable is in multiple positions in the second variable.
I've used the name mymember() for this predicate, so as not to conflict with GNU Prolog's builtin member() predicate. My knowledge base now looks like this:
mymember(X,[X|_]).
mymember(X,[_|T]) :- mymember(X,T).
not(A) :- \+ call(A).
set([],[]).
set([H|T],[H|Out]) :-
not(mymember(H,T)),
set(T,Out).
set([H|T],Out) :-
mymember(H,T),
set(T,Out).
So, mymember(1, [1, 1, 1]). evaluates as true in three different ways:
| ?- mymember(1, [1, 1, 1]).
true ? a
true
true
no
If you want to have only one answer, you're going to have to use a cut. Changing the first definition of mymember() to this:
mymember(X,[X|_]) :- !.
Solves your problem.
Furthermore, you can avoid not() altogether, if you wish, by defining a notamember() predicate yourself. The choice is yours.
A simpler (and likely faster) solution is to use library predicate sort/2 which remove duplicates in O(n log n). Definitely works in Yap prolog and SWIPL
You are on the right track... Stay pure---it's easy!
Use reified equality predicates =/3 and dif/3 in combination with if_/3, as implemented in Prolog union for A U B U C:
=(X, Y, R) :- X == Y, !, R = true.
=(X, Y, R) :- ?=(X, Y), !, R = false. % syntactically different
=(X, Y, R) :- X \= Y, !, R = false. % semantically different
=(X, Y, R) :- R == true, !, X = Y.
=(X, X, true).
=(X, Y, false) :-
dif(X, Y).
% dif/3 is defined like (=)/3
dif(X, Y, R) :- X == Y, !, R = false.
dif(X, Y, R) :- ?=(X, Y), !, R = true. % syntactically different
dif(X, Y, R) :- X \= Y, !, R = true. % semantically different
dif(X, Y, R) :- R == true, !, X \= Y.
dif(X, Y, true) :- % succeed first!
dif(X, Y).
dif(X, X, false).
if_(C_1, Then_0, Else_0) :-
call(C_1, Truth),
functor(Truth,_,0), % safety check
( Truth == true -> Then_0 ; Truth == false, Else_0 ).
Based on these predicates we build a reified membership predicate list_item_isMember/3. It is semantically equivalent with memberd_truth/3 by #false. We rearrange the argument order so the list is the 1st argument. This enables first-argument indexing which prevents leaving useless choice-points behind as memberd_truth/3 would create.
list_item_isMember([],_,false).
list_item_isMember([X|Xs],E,Truth) :-
if_(E = X, Truth = true, list_item_isMember(Xs,E,Truth)).
list_set([],[]).
list_set([X|Xs],Ys) :-
if_(list_item_isMember(Xs,X), Ys = Ys0, Ys = [X|Ys0]),
list_set(Xs,Ys0).
A simple query shows that all redundant answers have been eliminated and that the goal succeeds without leaving any choice-points behind:
?- list_set([1,2,3,4,1,2,3,4,1,2,3,1,2,1],Xs).
Xs = [4,3,2,1]. % succeeds deterministically
Edit 2015-04-23
I was inspired by #Ludwig's answer of set/2, which goes like this:
set([],[]).
set([H|T],[H|T1]) :- subtract(T,[H],T2), set(T2,T1).
SWI-Prolog's builtin predicate subtract/3 can be non-monotone, which may restrict its use. list_item_subtracted/3 is a monotone variant of it:
list_item_subtracted([],_,[]).
list_item_subtracted([A|As],E,Bs1) :-
if_(dif(A,E), Bs1 = [A|Bs], Bs = Bs1),
list_item_subtracted(As,E,Bs).
list_setB/2 is like set/2, but is based on list_item_subtracted/3---not subtract/3:
list_setB([],[]).
list_setB([X|Xs1],[X|Ys]) :-
list_item_subtracted(Xs1,X,Xs),
list_setB(Xs,Ys).
The following queries compare list_set/2 and list_setB/2:
?- list_set([1,2,3,4,1,2,3,4,1,2,3,1,2,1], Xs).
Xs = [4,3,2,1]. % succeeds deterministically
?- list_setB([1,2,3,4,1,2,3,4,1,2,3,1,2,1],Xs).
Xs = [1,2,3,4]. % succeeds deterministically
?- list_set(Xs,[a,b]).
Xs = [a,b]
; Xs = [a,b,b]
; Xs = [a,b,b,b]
... % does not terminate universally
?- list_setB(Xs,[a,b]).
Xs = [a,b]
; Xs = [a,b,b]
; Xs = [a,b,b,b]
... % does not terminate universally
I think that a better way to do this would be:
set([], []).
set([H|T], [H|T1]) :- subtract(T, [H], T2), set(T2, T1).
So, for example ?- set([1,4,1,1,3,4],S) give you as output:
S = [1, 4, 3]
Adding my answer to this old thread:
notmember(_,[]).
notmember(X,[H|T]):-X\=H,notmember(X,T).
set([],[]).
set([H|T],S):-set(T,S),member(H,S).
set([H|T],[H|S]):-set(T,S),not(member(H,S)).
The only virtue of this solution is that it uses only those predicates that have been introduced by the point where this exercise appears in the original text.
This works without cut, but it needs more lines and another argument.
If I change the [H2|T2] to S on line three, it will produce multiple results. I don't understand why.
setb([],[],_).
setb([H|T],[H|T2],A) :- not(member(H,A)),setb(T,T2,[H|A]).
setb([H|T],[H2|T2],A) :- member(H,A),setb(T,[H2|T2],A).
setb([H|T],[],A) :- member(H,A),setb(T,[],A).
set(L,S) :- setb(L,S,[]).
You just have to stop the backtracking of Prolog.
enter code here
member(X,[X|_]):- !.
member(X,[_|T]) :- member(X,T).
set([],[]).
set([H|T],[H|Out]) :-
not(member(H,T)),
!,
set(T,Out).
set([H|T],Out) :-
member(H,T),
set(T,Out).
Using the support function mymember of Tim, you can do this if the order of elements in the set isn't important:
mymember(X,[X|_]).
mymember(X,[_|T]) :- mymember(X,T).
mkset([],[]).
mkset([T|C], S) :- mymember(T,C),!, mkset(C,S).
mkset([T|C], S) :- mkset(C,Z), S=[T|Z].
So, for example ?- mkset([1,4,1,1,3,4],S) give you as output:
S = [1, 3, 4]
but, if you want a set with the elements ordered like in the list you can use:
mkset2([],[], _).
mkset2([T|C], S, D) :- mkset2(C,Z,[T|D]), ((mymember(T,D), S=Z,!) ; S=[T|Z]).
mkset(L, S) :- mkset2(L,S,[]).
This solution, with the same input of the previous example, give to you:
S = [1, 4, 3]
This time the elements are in the same order as they appear in the input list.
/* Remove duplicates from a list without accumulator */
our_member(A,[A|Rest]).
our_member(A, [_|Rest]):-
our_member(A, Rest).
remove_dup([],[]):-!.
remove_dup([X|Rest],L):-
our_member(X,Rest),!,
remove_dup(Rest,L).
remove_dup([X|Rest],[X|L]):-
remove_dup(Rest,L).