Reputation: 35
zebra_owner(Owner) :-
houses(Hs),
member(h(Owner,zebra,_,_,_), Hs).
water_drinker(Drinker) :-
houses(Hs),
member(h(Drinker,_,_,water,_), Hs).
houses(Hs) :-
length(Hs, 5), % 1
member(h(english,_,_,_,red), Hs), % 2
member(h(spanish,dog,_,_,_), Hs), % 3
member(h(_,_,_,coffee,green), Hs), % 4
member(h(ukrainian,_,_,tea,_), Hs), % 5
adjacent(h(_,_,_,_,green), h(_,_,_,_,white), Hs), % 6
member(h(_,snake,winston,_,_), Hs), % 7
member(h(_,_,kool,_,yellow), Hs), % 8
Hs = [_,_,h(_,_,_,milk,_),_,_], % 9
Hs = [h(norwegian,_,_,_,_)|_], % 10
adjacent(h(_,fox,_,_,_), h(_,_,chesterfield,_,_), Hs), % 11
adjacent(h(_,_,kool,_,_), h(_,horse,_,_,_), Hs), % 12
member(h(_,_,lucky,juice,_), Hs), % 13
member(h(japanese,_,kent,_,_), Hs), % 14
adjacent(h(norwegian,_,_,_,_), h(_,_,_,_,blue), Hs), % 15
member(h(_,_,_,water,_), Hs), % one of them drinks water
member(h(_,zebra,_,_,_), Hs). % one of them owns a zebra
adjacent(A, B, Ls) :- append(_, [A,B|_], Ls).
adjacent(A, B, Ls) :- append(_, [B,A|_], Ls).
How come the houses(Hs)
predicate not fail the various member(elem, list)
checks, if the list is actually empty all the time? I know it might sound like a dumb question, but wrapping my head around Prolog is actually hard, especially after years of Object-oriented programming. Any help is appreciated!
Edit: I didn't mention the query I was asking prolog, which is this zebra_owner(Owner)
Edit 2: Also posting the text of the problem (which is kinda famous) for reference:
Who owns the zebra and who drinks water?
Upvotes: 0
Views: 1110
Reputation: 9378
How come the Houses(Hs) predicate not fail the various member(elem, list) checks, if the list is actually empty all the time?
That's because the list isn't actually empty! The empty list in Prolog is []
. It contains no elements.
But the list inside a call to houses(Hs)
is controlled by the first goal in that predicate, namely length(Hs, 5)
. What does this goal mean?
An important thing to learn about Prolog is that a goal or query doesn't just mean "is this statement true?". A Prolog goal or query means "under what circumstances is this statement true?". Prolog will try to do work to describe circumstances to you under which your query becomes true.
So even if we know absolutely nothing about Hs
before, when executing this length
query, GNU Prolog says:
| ?- length(Hs, 5).
Hs = [_,_,_,_,_]
So length(Hs, 5)
becomes true if Hs
is of the form [_, _, _, _, _]
. This is not an empty list. It is not even a possibly empty list. It is a list that definitely contains exactly five elements. We don't know anything about those elements yet! But the length of the list is definitely fixed.
Maybe you got mislead by the fact that Prolog allows you to talk about a list that definitely has elements but whose elements are not yet known. This is a concept that is not possible in typical object oriented languages. But the fact that we don't know the elements doesn't mean that there is nothing there, i.e., that the list is empty.
As for how the member
calls succeed: Again, they aren't just checks for "is X
a member of Hs
". They are questions meaning "under what circumstances is X
a member of Hs
?". Again, Prolog will do some work for you to describe those circumstances:
| ?- length(Hs, 5), member(x, Hs).
Hs = [x,_,_,_,_] ? ;
Hs = [_,x,_,_,_] ? ;
Hs = [_,_,x,_,_] ? ;
Hs = [_,_,_,x,_] ? ;
Hs = [_,_,_,_,x]
So x
is a member of Hs
if x
is the first element of Hs
, or the second, or the third, or so on. In each of these cases, "describing the circumstances" means that Prolog actually binds the appropriate element of the list (which before was a variable) to the element x
. For each of these possibilities, further computations following the member
goal could further instantiate the list. This is what builds up the solutions to the Zebra puzzle: Instead of just answering "yes" to the question "does the puzzle have a solution", Prolog builds up a data structure actually describing a solution.
Upvotes: 1
Reputation: 71070
The houses list Hs
is not empty at all, ever. It is created right at the very beginning with
length(Hs, 5)
So it is a list with five initially uninitialized logical variables, which get instantiated by all the subsequent goals when they are called in turn, in particular by those same member/2
goals you mention.
To see an example of this, try:
32 ?- L=[A,B,C], member(1, L).
L = [1, B, C] ;
L = [A, 1, C] ; % three solutions are found by Prolog
L = [A, B, 1]. % in turn, one after another
Those calls which can't be fulfilled (where no instantiation of the remaining free logical variables is possible) cause that specific search branch to fail.
An example:
33 ?- L=[1,2,C], member(3,L). % a check succeeds, while
L = [1, 2, 3], C = 3. % instantiating the `C` logvar
34 ?- L=[1,2,3], member(3,L). % a check succeeds
L = [1, 2, 3].
35 ?- L=[1,2,3], member(4,L). % a check fails
false.
Only successful instantiations remain, in the end, thus forming the solution, when all the logical variables in Hs
become fully instantiated, ground.
Upvotes: 1