Related
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
I had a quick question re. existential qualifier using setof in prolog (i.e. ^).
using SICStus it seems that (despite what a number of websites claim), S does indeed appear to be quantified in the code below (using the bog standard, mother of / child of facts, which i havent included here):
child(M,F,C) :- setof(X,(mother(S,X)),C).
i check the unification using:
child(M,F,C) :- setof(X-S,(mother(S,X)),C).
so the following code, with the existential operator seem to make no difference:
child(M,F,C) :- setof(X,S^(mother(S,X)),C).
Any ideas why this is? What would be a situation where you would need the unifier then?
thanks!
Ok, I'm not sure I can explain it perfectly, but let me try.
It has to do with the fact that you are querying over a 2-ary relation, mother/2. In that case using X-S as the template has a similar effect on the result set C as using S^ in front of the goal. In X-S you are using both variables in the template, and therefore each possible binding of X and S is included in C. You get the same effect using S^ in front of the goal, as this is saying "ignore bindings of S when constructing the result".
But the difference between the two becomes clearer when you query over a 3-ary relation. The SWI manual has this example:
foo(a, b, c).
foo(a, b, d).
foo(b, c, e).
foo(b, c, f).
foo(c, c, g).
Now do similar queries as in your example
setof(X-Z, foo(X,Y,Z), C).
and
setof(Z, X^foo(X,Y,Z), C).
and you get different results.
It's not just checking unification, X-Z effectively changes your result set.
Hope that helps.
Edit: Maybe it clarifies things when I include the results of the two queries above. The first one goes like this:
?- setof(X-Z, foo(X,Y,Z), C).
Y = b
C = [a-c, a-d] ;
Y = c
C = [b-e, b-f, c-g] ;
No
The second one yields:
?- setof(Z, X^foo(X,Y,Z), C).
Y = b
C = [c, d] ;
Y = c
C = [e, f, g] ;
No
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 have a database in Prolog like this:
connection(a,b,bus)
connection(b,c,metro)
connection(b,d,taxi)
connection(d,e,bus)
What I want is the rules I need to apply so I can ask the question: "transport(a,c)" and it answers: "bus" and "metro"
Is that possible to define 1 or 2 rules so that the query "transport(a,c)" works ?
you should see the database like:
connection(Departure,Arrive,Transport).
so that... connection(D,A,T).
then the rules are:
connection(D,A,T):- traject(D,A,T).
connection(D,A,T):- traject(D,X,T1), traject(X,A,T2).
where...traject(Departure, X, Transport1) and traject(X, Arrival, Transport2)
and the query should be something like:
transport(a,c,T1). and
transport(a,c,T2).
and then the answer should come:
T1 = bus
T2 = metro
I would try this:
transport(A, B, [Method]) :- connection(A, B, Method).
transport(A, C, [Method|Others]) :-
connection(A, B, Method),
transport(B, C, Others).
The base case here is that you have a direct connection. The inductive case is to find a connection and then recur from the intermediate. Note that you will get an infinite regress if you try using transport/3 twice in the body instead of connection/3 and then transport/3! Try it and see!
This seems to work for the inputs I expect:
?- transport(a, c, M).
M = [bus, metro] ;
false.
?- transport(a, d, M).
M = [bus, taxi] ;
false.
?- transport(a, e, M).
M = [bus, taxi, bus] ;
false.
Hope this helps!
I had a quick question re. existential qualifier using setof in prolog (i.e. ^).
using SICStus it seems that (despite what a number of websites claim), S does indeed appear to be quantified in the code below (using the bog standard, mother of / child of facts, which i havent included here):
child(M,F,C) :- setof(X,(mother(S,X)),C).
i check the unification using:
child(M,F,C) :- setof(X-S,(mother(S,X)),C).
so the following code, with the existential operator seem to make no difference:
child(M,F,C) :- setof(X,S^(mother(S,X)),C).
Any ideas why this is? What would be a situation where you would need the unifier then?
thanks!
Ok, I'm not sure I can explain it perfectly, but let me try.
It has to do with the fact that you are querying over a 2-ary relation, mother/2. In that case using X-S as the template has a similar effect on the result set C as using S^ in front of the goal. In X-S you are using both variables in the template, and therefore each possible binding of X and S is included in C. You get the same effect using S^ in front of the goal, as this is saying "ignore bindings of S when constructing the result".
But the difference between the two becomes clearer when you query over a 3-ary relation. The SWI manual has this example:
foo(a, b, c).
foo(a, b, d).
foo(b, c, e).
foo(b, c, f).
foo(c, c, g).
Now do similar queries as in your example
setof(X-Z, foo(X,Y,Z), C).
and
setof(Z, X^foo(X,Y,Z), C).
and you get different results.
It's not just checking unification, X-Z effectively changes your result set.
Hope that helps.
Edit: Maybe it clarifies things when I include the results of the two queries above. The first one goes like this:
?- setof(X-Z, foo(X,Y,Z), C).
Y = b
C = [a-c, a-d] ;
Y = c
C = [b-e, b-f, c-g] ;
No
The second one yields:
?- setof(Z, X^foo(X,Y,Z), C).
Y = b
C = [c, d] ;
Y = c
C = [e, f, g] ;
No