%   File   : LAZY.PL
%   Author : R.A.O'Keefe
%   Updated: 30 October 1983
%   Mods for NIP: Ken Johnson 18-6-87
%   Purpose: Lazy lists in Prolog.
%   Needs  : APPLY


%   Note: this code is "pure" only in the sense that it has no side-
%   effects.  It does rely on the 'var' metalogical predicate and cuts.
%   The lists are a little bit too eager to really be called lazy, but
%   if you look at N elements it is true that only N+1 will be computed.
%   Really lazy lists would compute N.  If you backtrack, the computed
%   elements will be undone just like other Prolog data structures, a
%   Prolog system with "intelligent backtracking" might not do that.


%   A lazy list is a pair consisting of a normal Prolog list (usually
%   ending with an unbound variable) and a goal which may be used to
%   generate new elements.  The idea is that [X0,X1,X2,...]/R should
%   satisfy X0 R X1, X1 R X2, ...  These objects should only be used
%   as arguments to these predicates.

%   An example
%
%   ?-	make_lazy(0,succ,List),		% List is the list [0,1,2....]
%	head_lazy(List,H),		% H is 0
%	tail_lazy(List,T).		% T is [1,2,3...]
%					  where [0,1,2...] and [1,2,3...]
%					  are represented in a special form
%					  e.g. [0 | _1]/succ

make_lazy(First, Pred, [First|_]/Pred).


head_lazy([Head|_]/_, Head).


tail_lazy([_|Tail]/Pred, Tail/Pred) :-
	nonvar(Tail),
	!.	%  delete this clause to get logic

tail_lazy([Head|Tail]/Step, Tail/Step) :-
	apply(Step, [Head,Next]),
		Tail = [Next|_].

member_check_lazy(Thing, LazyList) :-
	head_lazy(LazyList, Thing),
	!.

member_check_lazy(Thing, LazyList) :-
	tail_lazy(LazyList, LazyTail),
	member_check_lazy(Thing, LazyTail).

