[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]


I brought the following proposal up during the December X3J13 meeting,
and it was requested that I send it to the list to allow for easier
digesting and further discussion.

We were discussing the pros and cons of merging the function and value
namespaces.  One of the issues used to support the single namespace is
that functional arguments are clumsy to use when FUNCALL is required,
and this may inhibit people from using high-order function composition.
I'm not sure I really agree that it is a significant deterrent, and
there are reasonable arguments in favor of requiring FUNCALL, but for
the purpose of this discussion let's assume that it is.

So, the one-namespace people argue that
          (defun twice (fun)
            #'(lambda (x) (fun (fun x))))
is clearer than
          (defun twice (fun)
            #'(lambda (x) (funcall fun (funcall fun x))))

This is then used as an argument that the value and function cells of
variables should be identical.  My proposal allows functional arguments
to be called without using FUNCALL, but still retaining the distinct
namespaces.  My version of the above function would be
          (defun twice (&function fun)
            #'(lambda (x) (fun (fun x))))
The keyword &function in the lambda list indicates that the functional
interpretation of the following parameter should be bound, rather than
the value interpretation.  This is analogous to the distinction between

This keyword also serves a secondary function, that of documenting the
fact that a particular parameter is expected to be a function.  This is
useful for programmers, and compilers can also assume a default
declaration for the parameter.

One of the issues that was brought up when I proposed this at the
meeting is that it lacks one important feature that FLET has: the lambda
list of the local function.  This could be solved in two ways.  First,
the &function syntax could be extended, so that it is
          &function name lambda-list
I don't really care for this, because it puts a whole lot of stuff in the
outer function's lambda list, and because two list elements are used
for one parameter (the latter could be dealt with by making it
          &function (name lambda-list)
).  The other solution is to use a declaration at the beginning of the
function body to specify the calling sequence.  This would be necessary
in order to specify the types of the arguments.  The two mechanisms
could be combined, so that the syntax would be
          &function (name arg-typespecs)
since there would be no use for argument names anyway (except for
self-documentation purposes).

&function can also be described in terms of a source transformation.
The example function could be rewritten as
          (defun twice (g0001)
            (flet ((fun (&rest args) (apply g0001 args)))
              #'(lambda (x) (fun (fun x)))))
Of course, it gets more complicated when the ideas for specifying the
arguments are added, but no one ever said compiler writing was easy.