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