206 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Prolog
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Prolog
		
	
	
	
	
	
/*
 | 
						|
    Author:        Ulrich Neumerkel
 | 
						|
    E-mail:        ulrich@complang.tuwien.ac.at
 | 
						|
    Copyright (C): 2009 Ulrich Neumerkel. All rights reserved.
 | 
						|
 | 
						|
Redistribution and use in source and binary forms, with or without
 | 
						|
modification, are permitted provided that the following conditions are
 | 
						|
met:
 | 
						|
 | 
						|
1. Redistributions of source code must retain the above copyright
 | 
						|
   notice, this list of conditions and the following disclaimer.
 | 
						|
 | 
						|
2. Redistributions in binary form must reproduce the above copyright
 | 
						|
   notice, this list of conditions and the following disclaimer in the
 | 
						|
   documentation and/or other materials provided with the distribution.
 | 
						|
 | 
						|
THIS SOFTWARE IS PROVIDED BY Ulrich Neumerkel ``AS IS'' AND ANY
 | 
						|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
						|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Ulrich Neumerkel OR
 | 
						|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
						|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
						|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
						|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 | 
						|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
						|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
						|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 | 
						|
The views and conclusions contained in the software and documentation
 | 
						|
are those of the authors and should not be interpreted as representing
 | 
						|
official policies, either expressed or implied, of Ulrich Neumerkel.
 | 
						|
 | 
						|
 | 
						|
 | 
						|
*/
 | 
						|
 | 
						|
:- module(lambda, [
 | 
						|
		   (^)/3, (^)/4, (^)/5, (^)/6, (^)/7, (^)/8, (^)/9,
 | 
						|
		   (\)/1, (\)/2, (\)/3, (\)/4, (\)/5, (\)/6, (\)/7,
 | 
						|
		   (+\)/2, (+\)/3, (+\)/4, (+\)/5, (+\)/6, (+\)/7,
 | 
						|
		   op(201,xfx,+\)]).
 | 
						|
 | 
						|
/** <module> Lambda expressions
 | 
						|
@ingroup YAPLibrary
 | 
						|
 | 
						|
This library provides lambda expressions to simplify higher order
 | 
						|
programming based on call/N.
 | 
						|
 | 
						|
Lambda expressions are represented by ordinary Prolog terms.
 | 
						|
There are two kinds of lambda expressions:
 | 
						|
 | 
						|
    Free+\X1^X2^ ..^XN^Goal
 | 
						|
 | 
						|
         \X1^X2^ ..^XN^Goal
 | 
						|
 | 
						|
The second is a shorthand for t+\X1^X2^..^XN^Goal.
 | 
						|
 | 
						|
Xi are the parameters.
 | 
						|
 | 
						|
Goal is a goal or continuation. Syntax note: Operators within Goal
 | 
						|
require parentheses due to the low precedence of the ^ operator.
 | 
						|
 | 
						|
Free contains variables that are valid outside the scope of the lambda
 | 
						|
expression. They are thus free variables within.
 | 
						|
 | 
						|
All other variables of Goal are considered local variables. They must
 | 
						|
not appear outside the lambda expression. This restriction is
 | 
						|
currently not checked. Violations may lead to unexpected bindings.
 | 
						|
 | 
						|
In the following example the parentheses around X>3 are necessary.
 | 
						|
 | 
						|
==
 | 
						|
?- use_module(library(lambda)).
 | 
						|
?- use_module(library(apply)).
 | 
						|
 | 
						|
?- maplist(\X^(X>3),[4,5,9]).
 | 
						|
true.
 | 
						|
==
 | 
						|
 | 
						|
In the following X is a variable that is shared by both instances of
 | 
						|
the lambda expression. The second query illustrates the cooperation of
 | 
						|
continuations and lambdas. The lambda expression is in this case a
 | 
						|
continuation expecting a further argument.
 | 
						|
 | 
						|
==
 | 
						|
?- Xs = [A,B], maplist(X+\Y^dif(X,Y), Xs).
 | 
						|
Xs = [A, B],
 | 
						|
dif(X, A),
 | 
						|
dif(X, B).
 | 
						|
 | 
						|
?- Xs = [A,B], maplist(X+\dif(X), Xs).
 | 
						|
Xs = [A, B],
 | 
						|
dif(X, A),
 | 
						|
dif(X, B).
 | 
						|
==
 | 
						|
 | 
						|
The following queries are all equivalent. To see this, use
 | 
						|
the fact f(x,y).
 | 
						|
==
 | 
						|
?- call(f,A1,A2).
 | 
						|
?- call(\X^f(X),A1,A2).
 | 
						|
?- call(\X^Y^f(X,Y), A1,A2).
 | 
						|
?- call(\X^(X+\Y^f(X,Y)), A1,A2).
 | 
						|
?- call(call(f, A1),A2).
 | 
						|
?- call(f(A1),A2).
 | 
						|
?- f(A1,A2).
 | 
						|
A1 = x,
 | 
						|
A2 = y.
 | 
						|
==
 | 
						|
 | 
						|
Further discussions
 | 
						|
http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/ISO-Hiord
 | 
						|
 | 
						|
@tbd Static expansion similar to apply_macros.
 | 
						|
@author Ulrich Neumerkel
 | 
						|
*/
 | 
						|
 | 
						|
:- meta_predicate no_hat_call(0).
 | 
						|
 | 
						|
:- meta_predicate
 | 
						|
	^(?,0,?),
 | 
						|
	^(?,1,?,?),
 | 
						|
	^(?,2,?,?,?),
 | 
						|
	^(?,3,?,?,?,?),
 | 
						|
	^(?,4,?,?,?,?,?).
 | 
						|
 | 
						|
^(V1,Goal,V1) :-
 | 
						|
   no_hat_call(Goal).
 | 
						|
^(V1,Goal,V1,V2) :-
 | 
						|
   call(Goal,V2).
 | 
						|
^(V1,Goal,V1,V2,V3) :-
 | 
						|
   call(Goal,V2,V3).
 | 
						|
^(V1,Goal,V1,V2,V3,V4) :-
 | 
						|
   call(Goal,V2,V3,V4).
 | 
						|
^(V1,Goal,V1,V2,V3,V4,V5) :-
 | 
						|
   call(Goal,V2,V3,V4,V5).
 | 
						|
^(V1,Goal,V1,V2,V3,V4,V5,V6) :-
 | 
						|
   call(Goal,V2,V3,V4,V5,V6).
 | 
						|
^(V1,Goal,V1,V2,V3,V4,V5,V6,V7) :-
 | 
						|
   call(Goal,V2,V3,V4,V5,V6,V7).
 | 
						|
 | 
						|
:- meta_predicate
 | 
						|
	\(0),
 | 
						|
	\(1,?),
 | 
						|
	\(2,?,?),
 | 
						|
	\(3,?,?,?),
 | 
						|
	\(4,?,?,?,?),
 | 
						|
	\(5,?,?,?,?,?),
 | 
						|
	\(6,?,?,?,?,?,?).
 | 
						|
 | 
						|
\(FC) :-
 | 
						|
   copy_term_nat(FC,C),no_hat_call(C).
 | 
						|
\(FC,V1) :-
 | 
						|
   copy_term_nat(FC,C),call(C,V1).
 | 
						|
\(FC,V1,V2) :-
 | 
						|
   copy_term_nat(FC,C),call(C,V1,V2).
 | 
						|
\(FC,V1,V2,V3) :-
 | 
						|
   copy_term_nat(FC,C),call(C,V1,V2,V3).
 | 
						|
\(FC,V1,V2,V3,V4) :-
 | 
						|
   copy_term_nat(FC,C),call(C,V1,V2,V3,V4).
 | 
						|
\(FC,V1,V2,V3,V4,V5) :-
 | 
						|
   copy_term_nat(FC,C),call(C,V1,V2,V3,V4,V5).
 | 
						|
\(FC,V1,V2,V3,V4,V5,V6) :-
 | 
						|
   copy_term_nat(FC,C),call(C,V1,V2,V3,V4,V5,V6).
 | 
						|
 | 
						|
:- meta_predicate
 | 
						|
	+\(?,0),
 | 
						|
	+\(?,1,?),
 | 
						|
	+\(?,2,?,?),
 | 
						|
	+\(?,3,?,?,?),
 | 
						|
	+\(?,4,?,?,?,?),
 | 
						|
	+\(?,5,?,?,?,?,?),
 | 
						|
	+\(?,6,?,?,?,?,?,?).
 | 
						|
 | 
						|
+\(GV,FC) :-
 | 
						|
   copy_term_nat(GV+FC,GV+C),no_hat_call(C).
 | 
						|
+\(GV,FC,V1) :-
 | 
						|
   copy_term_nat(GV+FC,GV+C),call(C,V1).
 | 
						|
+\(GV,FC,V1,V2) :-
 | 
						|
   copy_term_nat(GV+FC,GV+C),call(C,V1,V2).
 | 
						|
+\(GV,FC,V1,V2,V3) :-
 | 
						|
   copy_term_nat(GV+FC,GV+C),call(C,V1,V2,V3).
 | 
						|
+\(GV,FC,V1,V2,V3,V4) :-
 | 
						|
   copy_term_nat(GV+FC,GV+C),call(C,V1,V2,V3,V4).
 | 
						|
+\(GV,FC,V1,V2,V3,V4,V5) :-
 | 
						|
   copy_term_nat(GV+FC,GV+C),call(C,V1,V2,V3,V4,V5).
 | 
						|
+\(GV,FC,V1,V2,V3,V4,V5,V6) :-
 | 
						|
   copy_term_nat(GV+FC,GV+C),call(C,V1,V2,V3,V4,V5,V6).
 | 
						|
 | 
						|
 | 
						|
%% no_hat_call(:Goal)
 | 
						|
%
 | 
						|
% Like call, but issues an error for a goal (^)/2.  Such goals are
 | 
						|
% likely the result of an insufficient number of arguments.
 | 
						|
 | 
						|
no_hat_call(MGoal) :-
 | 
						|
   strip_module(MGoal, _, Goal),
 | 
						|
   (  nonvar(Goal),
 | 
						|
      Goal = (_^_)
 | 
						|
   -> throw(error(existence_error(lambda_parameters,Goal),_))
 | 
						|
   ;  call(MGoal)
 | 
						|
   ).
 | 
						|
 | 
						|
% I would like to replace this by:
 | 
						|
% V1^Goal :- throw(error(existence_error(lambda_parameters,V1^Goal),_)).
 |