Finding the last element of a list in Prolog seems to be straightforward
my_last([A], A).
my_last([_,A|T], E) :-
my_last([A|T], E).
Unfortunately, this predicate is non-deterministic, no matter how "instantiated" the actual parameters are.
?- my_last([1,2,3], 3).
true ;
false.
Looking at the implementation of the nth0/3
here https://github.com/mthom/scryer-prolog/blob/master/src/lib/lists.pl, there's a "trick" to guard the actual predicates with integer(N) ->
which acts like a preprocessor and splits the predicate into a deterministic and a non-deterministic branches.
So how do I define such preprocessor conditions for my_last/2
, in order to make it deterministic for the case where the tail of the list is not a variable? Can it be done efficiently?
Can see swi-prolog's code:
?- listing(last).
lists:last([X|Xs], Last) :-
last_(Xs, X, Last).
?- listing(last_).
lists:last_([], Last, Last).
lists:last_([X|Xs], _, Last) :-
last_(Xs, X, Last).
This is using empty list []
vs head-and-tail [Head|Tail]
distinction in the first argument, to be deterministic. More info at Determining if a list is empty or not