`help/text/lambda` := TEXT(
`FUNCTION: lambda - lambda abstraction (from lambda calculus)`,
``,
`CALLING SEQUENCES: lambda(x,f);  or  lambda(x1,...,xn,f);`,
``,
`PARAMETERS:`,
`   x,x1,x2,... - variable name or a list of variable names`,
`   f - algebraic expression (function of the variables)`,
``,
`SYNOPSIS:`,
`- This function implements the lambda function of lambda calculus.`,
`  If x is a name, then lambda(x,f(x)) converts the input "expression" to a`,
`  "function" of x.  The output is a Maple -> function of the form  x -> f(x) `,
`- If x is a list of names, then lambda([v1,...,vn],f) outputs`,
`  a function of m variables (possibly 0).  The output is a Maple -> function`,
`  of the form (v1,...,vm) -> f.`,
`- The case lambda(x1,x2,...,xn,f(x1,x2,...,xn)) is equivalent to repeated`,
`  application lambda, namely lambda(x1,lambda(x2,...,xn,f(x1,x2,...,xn)))`,
`- In the lambda calculus, functions of more than one variable are treated`,
`  in this way as repeated application of functions of one variable.`,
`  The Maple lambda function supports both.`,
``,
` NB: that lambda([],f) defines the nullary function  () -> f`,
` NB: that lambda(f) is the identity function.`,
``,
`EXAMPLES:`,
`> f := lambda(x,x^2+y+1/z);`,
`                                        2`,
`                             f := x -> x  + y + 1/z`,
``,
`> f(2);`,
`                                  4 + y + 1/z`,
``,
`> f := lambda([x,y],x^2+y+1/z);`,
`                                          2`,
`                           f := (x,y) -> x  + y + 1/z`,
``,
`> f(2,3);`,
`                                    7 + 1/z`,
``,
`> f := lambda([],x^2+y+1/z);`,
`                                        2`,
`                            f := () -> x  + y + 1/z`,
``,
`> f();`,
`                                   2`,
`                                  x  + y + 1/z`,
``,
`> f := lambda(x,y,x^2+y+1/z);`,
``,
`                    f := x -> subs({x = x}, y -> x^2+y+1/z)`,
``,
`> f(2);`,
`                                y -> 4 + y + 1/z`,
``,
`> g := lambda(y,x,x^2+y+1/z);`,
``,
`                    g := y -> subs({y = y}, x -> x^2+y+1/z)`,
``,
`> g(2);`,
`                                     2`,
`                               x -> x  + 2 + 1/z`,
``,
`> f(2)(3);`,
`                                    7 + 1/z`,
``,
`> g(3)(2);`,
`                                    7 + 1/z`
):
#
# The implementation produces funny looking subs calls in the resulting
# procedures.  These substitutions are implementing nested lexical
# scoping rules which Maple does not have.  Just ignore them.
#
# Author: MBM Nov/90
#

macro( GENSYM = readlib(`tools/gensym`) );

lambda := proc()
local f, x, n, i, t, X, Y, Yp;

f := args[nargs];
if nargs = 1 then RETURN(eval(f,1)) fi;

x := args[1];
if type(x,name) then x := [x] elif type(x,set) then x := [op(x)] fi;

if not type(x,list(name)) or nops(x) <> nops({op(x)}) then
	ERROR(`variables must be unique and of type name`) fi;

if not type(x,list(string)) then
	n := nops(x);
	X := [seq( GENSYM( cat('x',``.i) ), i=1..n )];
	RETURN( lambda( X, args[2..nargs-1],
		subs( [seq( x[i]=X[i], i=1..n )], eval(f,1) ) ) )
fi;

if nargs > 2 then f := lambda( args[2..nargs-1], eval(f,1) ) fi;

if has(eval(f,1), x) and hastype(eval(f,1),procedure) then
	Y := {seq( t = GENSYM(t), t=x )};
	Yp := {seq( rhs(t)=lhs(t), t=Y )};
	f := subs(Y, eval(f,1) );
	subs( {_PARMS=op(x),_SUBS=Yp,_BODY=eval(f,1)},
		_PARMS -> subs(_SUBS,_BODY) )
else subs( {_BODY=eval(f,1),_PARMS=op(x)}, _PARMS -> _BODY )
fi

end:

macro(GENSYM = GENSYM);

#save `lambda.m`;
#quit
