Reputation: 41
I am new to prolog and am basically trying to write a clause that would evaluate as true if a given item is the last item in a given list. Here is what I have:
last(X,[Y|X]).
last(X,[Y|Z]) :- last(X,Z).
I thought this would do the trick, but when I ask prolog:
?- last(c,[a,b,c]).
Prolog returns false. I tried the following query to see what Prolog thinks should fit my definition of last:
?- last(c,X).
X = [_G530|c] ;
X = [_G530, _G533|c] ;
X = [_G530, _G533, _G536|c]
So, what I am not sure about is why the "|" symbol is still in the list?
Update: last([c],[a,b,c]) produces the desired behavior. However, I'm not sure why my 1st argument has to be a list?
Upvotes: 4
Views: 39395
Reputation: 21
(a) using concatenation,
conc(_,[Item],List)
(b) Using without concatenation,
Last([Item],[Item]) :- Last(Item,[H|T]) , Last(Item,T)
Upvotes: 0
Reputation: 31
Why not just use append?
last(X,Y) :-
append(_,[X],Y).
http://www.swi-prolog.org/pldoc/man?predicate=append/3
Upvotes: 3
Reputation: 10102
Why not view things from a grammatical viewpoint. So what is the last element in a list?
last(X, Xs) :-
phrase( ( ..., [X] ), Xs).
... --> [] | [_], ... . % any sequence
Upvotes: 3
Reputation: 4078
Because the tail of a list is a list itself.
A list in Prolog can be seen as [H | T]
, where H
is the first element (the head), and T
(the tail) is a list of all other elements.
Your list [a, b, c]
is actually [a | [b | [c | [] ] ] ]
when you decompose it (the last tail is always an empty list):
List: [a, b, c] Head: a Tail: [b, c]
List: [b, c] Head: b Tail: [c]
List: [c] Head: c Tail: []
So when you get to the point where you're asking if last(c, [b, c])
, that decomposes to last(c, [b|[c]])
, which is why the first clause can't be instantiated, because X
can't be both c
and [c]
. That is why it did work when you asked last([c],[a,b,c])
.
The version proposed by alpha works, because it takes this into account:
% A list ends with an element if contains exactly that element.
last(X,[X]).
% A list ends with an element if its tail ends with that element.
% (Since we don't care about the head, we use an underscore).
last(X,[_|T]) :- last(X,T).
Upvotes: 2
Reputation: 318
You might want this:
last(X,[X]).
last(X,[_|Z]) :- last(X,Z).
The |
denotes a 'tail' or 'the rest of the list.'
With ?- last(c,X).
Prolog produces lists (according to your first definition) that have c as the last item.
When you query ?- last(c,[a,b,c]).
, it returns false because you haven't defined a case for a list of only one item [X]
or [X|[]]
. So it fails when list is shorter than two items.
However, last([c],[a,b,c])
succeeds because you get [b|_29]
or whatever denoting that the tail part might be any list. So it '_29' can be '[c]', satisfying the first definition like last([c],[b|[c]]).
Remember that a nonempty list in Prolog is actually a pair of the first list item (head) and a list of the rest (tail). Usually written as [head|tail].
Upvotes: 11