	  /***********  Lazy Evaluator for Equations   ************/

mode none.
closure none.

lazy([H|T])     equals [H|T].
lazy(univ(F,L)) equals lazy(kind(F),F,L). 
lazy(X)         equals X.   /* for constants */

lazy(user,F,L) equals lazy(clause(univ(F,red_args(L,mode(F))))).
lazy(_   ,F,L) equals univ(F,L). /* for constructors */

	red_args([],_) 		equals [].
	red_args([H|T],[HM|TM]) equals [check_modes(HM,H) | red_args(T,TM)].

		check_modes(lazy,X)  equals X.
		check_modes(_,   X)  equals lazy(X).

/*********  Constructors vs User-defined Functions ***********/

	kind(app)      equals user.
	kind(rev)      equals user.
	kind(nums)     equals user.
	kind(primes)   equals user.
	kind(sieve)    equals user.
	kind(relprime) equals user.
	kind(if)       equals user.
	kind(prefix)   equals user.
	kind(cons)     equals user.
	kind(_)        equals constructor.

/******** Assume Strictness Modes are given in advance *******/

        mode(if)     equals [strict,lazy,lazy].
	mode(nums)   equals [strict].	
	mode(prefix) equals [[strict|lazy],strict].
	mode(primes) equals [[strict|lazy]].
	mode(sieve)  equals [[strict|lazy],strict].
	mode(relprime) equals [strict,strict].
	mode(app)    equals [[lazy|lazy],lazy]. 	
	mode(rev)    equals [[lazy|lazy]].
	mode(len)    equals [[lazy|strict]].
	mode(succ)   equals [strict].
	mode(cons)   equals [strict,strict].

/********   Clauses for User-defined Equations   **********/

clause(rev([]))       equals [].
clause(rev([H|T]))    equals app(rev(T),[H]).
clause(app([],X))     equals X.
clause(app([H|T],X))  equals [H|app(T,X)]. 

clause(primes([H|T]))   equals  [H|primes(sieve(T,H))].
clause(sieve([H|T],N))  equals if(relprime(H,N), [H|sieve(T,N)], sieve(T,N)).
clause(relprime(H,N))   equals (H/N)*N <> H.
clause(nums(N))	        equals [N|nums(N+1)].

clause(prefix([H|T],0)) equals [].
clause(prefix([H|T],N)) equals cons(H,prefix(T,N-1)).
clause(cons(H,T))       equals [H|T].		

clause(if(true,X,Y))   equals X.
clause(if(false,X,Y))  equals Y.


/* Typical Goals and Answers:

|AS- lazy(rev([1,2,3,4,5])).
[5|app(app(app(app([], [4]), [3]), [2]), [1])]

|AS- lazy(prefix(rev([1,2,3,4,5]), 3)).
[5,4,3]

|AS- lazy(primes(nums(2))).
[2|primes(sieve(nums(3), 2))]

|AS- lazy(prefix(primes(nums(2)), 10)).
[2,3,5,7,11,13,17,19,23,29]

*/
