I think your primary question of how lists are represented as variables has been adequately answered, but I sense there are some other aspects to Prolog that need clarification.
To understand Prolog predicates and clauses, it's a good idea not to think of them as "functions" that "return" things, even metaphorically. It can lead you down the dark path of imperative thinking in Prolog. :)
In considering the predicate:
(1) member(X, [X|_]).
(2) member(X, [_|T]) :- member(X, T).
Think of member/2
as a relation which describes when element X
is a member of the list L
, and the clauses are the rules for determining when it is true.
I'll assume that you already know about how lists are represented in Prolog based upon other answers (e.g., Will Ness' detailed answer).
The first clause says:
(1) X
is a member of [X|_]
regardless of what the tail of the list [X|_]
is
In that notation, the variable _
represents the tail of list [X|_]
and X
represents the first element of that list. It's trivially true that X
is a member of this list, so member(X, [X|_]).
is a fact. It's true regardless of what the tail of the list is, so we just use _
(an anonymous variable) since this rule doesn't need the information. Prolog doesn't technically "throw the value away" but the programmer throws it away because the programmer isn't using it. If we had, instead, said, member(X, [X|T]).
that would work fine, but we're not using T
. Prolog might instantiate it, but it wouldn't be used. It's like assigning x = 3
in C but not using it's value. In this case, Prolog will indicate a warning about a "singleton" variable. Watch for those, because it often means you misspelled something or forgot something. :)
The next rule is recursive. It says:
(2) X
is a member of list [_|T]
if X
is a member of the tail (T
) of that list, regardless of what the first element of the list is
Here we're considering the less trivial case where the first element in the list may not be a match to X
, so the truth value of member(X, L)
depends, in this rule, upon the truth value of member(X, T)
where T
is the tail (everything but the first element) of L
. The rule does not unify member(X, [_|T])
with member(X, T)
, so it does not unify T
with [_|T]
as you might suppose. The :-
operator defines a rule or implication (note the if in the rule description). [N.B., If you were to unify these terms, it would be done with with the unification operator, =/2
: member(X, [_|T]) = member(X, T)
].
On the recursive query member(X, T)
, Prolog goes back to the top, the first rule, and attempts to unify the first argument X
with the head of the second argument (which is the original list minus its first element, or head) and, if it doesn't match, goes to rule #2 again, continually checking the tail as well, until it can unify. If it gets to the point where the tail is empty ([]
) and hasn't been able to unify X
with any elements, the predicate fails because there are no facts or rules that match member(X, [])
. However, if it does unify X
with an element, it succeeds (it does not "return a value* in the sense that a function would in other languages) and reveals the values of any variables it instantiated in the arguments in the process, or simply will succeed if all the arguments passed are already instantiated. If there are more rules to check after succeeding (there was what's called a choice point), it will (if you tell it to) go back and check for more solutions and, if it finds them, display them as well. Or display no
or false
if there are no more.
Looking at an example query, is b
a member of [a,b,c]
?
member(b, [a,b,c]).
Prolog will first try to unify the query with a fact or the head of a predicate. The first one it finds is:
member(X, [X|_]).
In attempting to unify, X = b
, but [a,b,c]
(or, [a|[b,c]]
in the head-tail notation) doesn't unify with [b|_](note the head elements
aand
b` mismatch). Prolog then moves on to the next clause:
member(X, [_|T]) :- member(X, T).
In unifying member(b, [a,b,c])
with the head, it comes up with:
member(b, [_|[b,c]]) :- member(b, [b,c]).
It now has the recursive query to chase down: member(b, [b,c])
. Since it's a new query, it starts at the top again and attempts to unify this with member(X, [X|_])
. Now, it's successful, because member(b, [b,c])
(or, member(b, [b|[c]])
) matches this pattern: member(b, [b|_])
.
Therefore, the member(b, [a,b,c]).
succeeds and Prolog will return "true". However, it's not done yet because it left what's called a choice point. Even though it matched member(b, [b,c])
with the first clause, it will still want to go back and find more cases that make it succeed, and there's still another clause to pursue. So, Prolog will go back and try member(b, [b,c])
against the second clause, matching member(b, [b|[c]])
to member(b, [_|[c]])
and doing another recursive query, member(b, [c])
and so on until it ultimately fails to find another solution. This is why the query looks something like this:
| ?- member(b, [a,b,c]).
true ? ;
no
| ?-
It first succeeds, but then we ask for more (with ;
) and it then fails (no
). This confuses some Prolog beginners, but it's because we've asked Prolog to get another solution, and it said there are none.
Because Prolog continues to try to find solutions (upon request), you can also use a variable in the query:
member(E, [a,b,c]).
This query runs the same way as the prior example, but now I have a variable as the first argument. Prolog will successfully match this to the first clause: member(E, [a,b,c])
unifies with member(X, [X|_])
via E = a
. So you'll see something like:
| ?- member(E, [a,b,c]).
E = a ?
If we now ask for more solutions with ;
, Prolog goes back and attempts the second clause, unifying member(E, [a|[b,c]])
with member(X, [_|T])
yielding _ = a
(which is ignored in the predicate) and T = [b,c]
. It then recursively queries, member(E, [b,c])
and, since it's a new query, goes back to the top and matches member(X, [X|_])
again, this time with E = b
. So we see:
| ?- member(E, [a,b,c]).
E = a ? ;
E = b ?
And so on. member(E, [a,b,c])
will find all the values of E
which make member(E, [a,b,c])
true and then finally fail after exhausting all the elements of [a,b,c]
).