zero-arity higher-order function terms and apply/1

Fergus Henderson fjh at cs.mu.oz.au
Tue Jul 22 01:28:07 AEST 1997


In email to me, Andrew Bromage wrote (and I replied)

bromage> I'm trying to implement a lazy stream using a type like this:
bromage> 
bromage> :- type e_stream --->
bromage> 		cons(int, e_stream)
bromage> 	;       closure((func) = e_stream).

fjh> You've just pointed out a compiler bug: that should be an error.
fjh> There is no such type as `(func) = e_stream'.

bromage> The problem is that I can't seem to call the zero-arity function
bromage> in the closure/1 functor. [...]
bromage> How do I call a zero-arity function that's in a variable?

fjh> You can't.  Well, actually it is worse than that, you can't even
fjh> put such a function in a variable in the first place, because
fjh> it's not possible to take the address of a zero-arity function.
fjh> 
fjh> Instead, use either `func(unit) = e_stream' (as you would do in ML,
fjh> although the spelling of unit as `()' is perhaps nicer),
fjh> or `pred(e_stream)'.

So I then started implementing a fix for the compiler bugs:

 | Fix a few places where the compiler was allowing zero-arity
 | higher-order function terms.  (There's no such thing, as is clear from
 | the Mercury Reference Manual.  The reason that they are not allowed is
 | this: if they were allowed, how would you create one?  Just mentioning
 | the name of a zero-arity function causes it to be evaluated, i.e. the
 | function's name denotes the function result, rather than the function
 | itself.  You could overload the name to mean both the function itself
 | and the function's result, but that would cause confusion, and the
 | overloading would cause problems for type checking and inference.)
 | 
 | compiler/prog_io_util.m:
 | 	Disallow zero-arity higher-order function modes and insts.
 | 
 | compiler/prog_io_goal.m:
 | 	Disallow zero-arity higher-order function lambda expressions.
 | 
 | compiler/module_qual.m:
 | 	Disallow zero-arity higher-order function types.

However, on second thoughts, it would be useful to allow zero-arity
higher-order function types.  To create one, you would have to use
a lambda expression.  E.g. given

	:- func foo((func) = T) = T.
	foo(X) = apply(X).

then you would have to write

	foo(func = math__pi)

rather than

	foo(math__pi).

This is in contrast to other higher-order function types, where
you can always just use the function name.  So it is a little
bit non-orthogonal.  However, as far as orthogonality goes, I
suppose it is no worse than disallowing zero-arity higher-order
function terms altogether.

So, this suggests the following alternative change:

 | Allow zero-arity higher-order function terms.
 | 
 | compiler/typecheck.m:
 | 	Allow apply/1.
 | 
 | doc/reference_manual.texi:
 | 	Document that zero-arity higher-order function types, 
 | 	insts, modes, lambda expressions, and applications
 | 	are allowed.

Comments?  Anyone want to review this change?

Index: ../compiler/typecheck.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/typecheck.m,v
retrieving revision 1.207
diff -u -r1.207 typecheck.m
--- typecheck.m	1997/06/29 23:11:36	1.207
+++ typecheck.m	1997/07/21 14:43:58
@@ -2174,7 +2174,7 @@
 builtin_apply_type(_TypeCheckInfo, Functor, Arity, ConsTypeInfos) :-
 	Functor = cons(unqualified(ApplyName), _),
 	( ApplyName = "apply" ; ApplyName = "" ),
-	Arity >= 2,
+	Arity >= 1,
 	Arity1 is Arity - 1,
 	higher_order_func_type(Arity1, TypeVarSet, FuncType, ArgTypes, RetType),
 	ConsTypeInfos = [cons_type_info(TypeVarSet, RetType,
@@ -3523,7 +3523,7 @@
 			[]
 		)
 	;
-		{ PredName = unqualified("apply"), Arity >= 2 }
+		{ PredName = unqualified("apply"), Arity >= 1 }
 	->
 		report_error_apply_instead_of_pred(TypeCheckInfo)
 	;
Index: ../doc/reference_manual.texi
===================================================================
RCS file: /home/staff/zs/imp/mercury/doc/reference_manual.texi,v
retrieving revision 1.57
diff -u -r1.57 reference_manual.texi
--- reference_manual.texi	1997/07/21 14:16:45	1.57
+++ reference_manual.texi	1997/07/21 15:14:24
@@ -684,10 +684,13 @@
 @end example
 
 @noindent
-where Var1, Var2, @dots{} are variables, Mode1, Mode2, @dots{} are
-modes (@pxref{Modes}), Det is a determinism (@pxref{Determinism}),
+where Var1, Var2, @dots{} are zero or more variables,
+Mode1, Mode2, @dots{} are zero or more modes (@pxref{Modes}),
+Det is a determinism (@pxref{Determinism}),
 and Goal is a goal (@pxref{Goals}). 
-It denotes a higher-order predicate or function term
+The @samp{:- Goal} part is optional;
+if it is not specified, then @samp{:- true} is assumed.
+A lambda expression denotes a higher-order predicate or function term
 whose value is the predicate or function of the specified arguments
 determined by the specified goal.
 @xref{Higher-order}.
@@ -701,7 +704,7 @@
 @end example
 
 @noindent
-where @var{N} >= 1, @var{Func} is a term of type
+where @var{N} >= 0, @var{Func} is a term of type
 @samp{func(T1, T2, ..., Tn) = T}, @var{FuncVar} is a variable
 of that type, and
 @var{Arg1}, @var{Arg2}, @dots{}, @var{ArgN} are terms of types
@@ -766,7 +769,8 @@
 and @code{string}.  (For @code{char}, the standard syntax suffices.)
 
 @item Predicate types: @code{pred}, @code{pred(T)}, @code{pred(T1, T2)}, @dots{}
- at itemx Function types: @code{func(T1) = T}, @code{func(T1, T2) = T}, @dots{}
+ at itemx Function types: @code{(func) = T}, @code{func(T1) = T},
+ at itemx @code{func(T1, T2) = T}, @dots{}
 These higher-order function and predicate types are used to pass procedure
 addresses and closures to other predicates.  @xref{Higher-order}.
 
@@ -798,7 +802,8 @@
 (Note there are @emph{three} dashes in that arrow.
 It should not be confused with the two-dash arrow used for DCGs
 or the one-dash arrow used for if-then-else.)
-If the @var{type} term is a functor of arity zero,
+If the @var{type} term is a functor of arity zero
+(i.e. one having zero arguments),
 it names a monomorphic type.
 Otherwise, it names a polymorphic type;
 the arguments of the functor must be distinct type variables.
@@ -1932,7 +1937,7 @@
 
 To create a higher-order predicate or function term, you can use
 a lambda expression, or, if the predicate or function has only one
-mode, you can just use its name.
+mode and it is not a zero-arity function, you can just use its name.
 For example, if you have declared a predicate
 
 @example
@@ -1987,7 +1992,8 @@
 If the predicate or function has more than one mode, you must use an explicit
 lambda expression to specify which mode you want.
 
-You can also create higher-order predicate terms by "currying",
+You can also create higher-order function terms of non-zero arity
+and higher-order predicate terms by "currying",
 i.e. specifying the first few arguments to a predicate or function, but
 leaving the remaining arguments unspecified.  For example, the
 unification
@@ -2008,6 +2014,11 @@
 binds @samp{Double} to a higher-order function term of type
 @samp{func(list(int)) = list(int)}.
 
+Higher-order function terms of zero arity can only be created using
+an explicit lambda expression; you have to use e.g. @samp{(func) = foo}
+rather than plain @samp{foo}, because the latter denotes the result
+of evaluating the function, rather than the function itself.
+
 Note that when constructing a higher-order term, you cannot just use
 the name of a builtin language construct such as @samp{=}, @samp{\=},
 @samp{call}, or @samp{apply}, and nor can such constructs be curried.  
@@ -2082,7 +2093,8 @@
 For functions, you use the builtin expression apply/N:
 
 @table @asis
- at item @code{apply(Closure1, Arg1)}
+ at item @code{apply(Closure)}
+ at itemx @code{apply(Closure1, Arg1)}
 @itemx @code{apply(Closure2, Arg1, Arg2)}
 @itemx @dots{}
 A higher-order function application.  Such a term denotes the
@@ -2180,6 +2192,7 @@
 pred(@var{Mode}) is @var{Determinism}
 pred(@var{Mode1}, @var{Mode2}) is @var{Determinism}
 @dots{}
+(func) = @var{Mode} is @var{Determinism}
 func(@var{Mode1}) = @var{Mode} is @var{Determinism}
 func(@var{Mode1}, @var{Mode2}) = @var{Mode} is @var{Determinism}
 @dots{}

-- 
Fergus Henderson <fjh at cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3         |     -- the last words of T. S. Garp.



More information about the developers mailing list