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

re: FUNCTIONP



> Date: Thu, 19 May 88 15:31:14 edt
> From: edu.berkeley.ucbvax!vax135!lcuxlj!ilan
> Subject: re: FUNCTIONP

> I agree FUNCTIONP isn't terribly useful - but p. 76 is pretty precise.
> I think the key is that the object "is suitable" for being
> a function (ignoring issues of whether you can redefine special-forms
> etc.)

You're right as far as the current (CLtL) intent of FUNCTIONP.
The (or a) problem is that one would like to be able to distinguish
between function objects as such and their names.  FUNCTIONP is
true of the names as well as the functions themselves.  That is,
we would like to be able to ask "is this really a function, and not
just a symbol or a list beginning with LAMBDA?"  Scheme has such
a test, namely PROCEDURE?

> To find out if something is really a (global) function would this 
> be good enough?
> 
> (DEFUN REALLY-A-FUNCTION-P (OBJECT)
>   (AND (FUNCTIONP OBJECT)
>        (FBOUNDP OBJECT)
>        (NOT (MACRO-FUNCTION OBJECT))
>        (NOT (SPECIAL-FORM-P OBJECT))))

It will work for global function names, that is: for symbols.  Note,
however, (CLtL, pages 90-91) that FBOUNDP et al are functions of
symbols, not of arbitrary objects.  They may well signal an error of
given an arbitrary object.  As a result, including (FUNCTIONP OBJECT)
in the AND doesn't accomplish very much: it doesn't exclude anything
that isn't also excluded (by being an error) later.  You would de
better to use (SYMBOLP OBJECT) instead.

Your predicate (using SYMBOLP) is nonetheless useful, but there is
another useful test that, in KCL, would be more like this:

   (defun function-object-p (x)
     (or (compiled-function-p x)
         (and (consp x)
              (member (car x)
                      '(LAMBDA-CLOSURE LAMBDA-BLOCK
                        LAMBDA-BLOCK-CLOSURE)))))

Note that FUNCTION tends to return an object for which REALLY-A-
FUNCTION-P (when using FUNCTIONP instead of SYMBOLP) signals an error
but for which FUNCTION-OBJECT-P returns true.  Consider the following
cases:

    #'car                 => #<compiled-function CAR>

    #'(lambda (x) x)      => (LAMBDA-CLOSURE () () () (X) X)

    (flet ((f (x) x))
      #'f)                => (LAMBDA-BLOCK-CLOSURE () () () F (X) X)

The results of these expressions are "function objects".
Unfortunately, there is no standard CL predicate that is true of
these objects and of nothing else.  Nor is it possible to define a
portable predicate, because the representation of interpreted
functions differs from CL to CL.  The one defined above is KCL-
specific.

Another problem is that Common Lisps are allowed to use lists
to represent functions.  (That's what KCL does.)  Then predicates
such as LISTP will be true of functions even thought we might
prefer that functios were a separate object type.

The proposal to x3j13 is, in part, to make FUNCTIONP be the standard
FUNCTION-OBJECT-P.  The idea is that function objects will be of type
FUNCTION, i.e. (TYPEP <some fn> 'FUNCTION) => <true>.  FUNCTIONP is
then the natural name of the predicate that makes the same test.

And, as has been noted elsewhere, FUNCTIONP is not very useful as it
is now.  We've just given two more examples: it was not needed to
define FUNCTION-OBJECT-P, nor was it very helpful in your REALLY-
A-FUNCTION-P.  Therefore, it is not much used and changing its meaning
will not do much harm.

> Definitely verbose and I too would prefer a builtin...
> 
> A real interpreted function would be:
> 
> (DEFUN INTERPRETED-FUNCTION-P (OBJECT)
>   (AND (REALLY-A-FUNCTION-P OBJECT)
>        (NOT (COMPILED-FUNCTION-P #'OBJECT))))

There two things wrong with this definition.  The first, mentioned
above, is that REALLY-A-FUNCTION-P works correctly only on symbols.
But of course you may only be interested in that case.  The second
problem would, however, remain; and it is that #'OBJECT will return
the functional interpretation of the symbol OBJECT where you want
instead to look at the functional interpretation of the value of
(the variable) OBJECT.  That is, you need:

     (not (compiled-function-p (symbol-value object)))

Note that there is no way to do this for function names defined
by FLET or LABELS.

Jeff Dalton,                      JANET: J.Dalton@uk.ac.ed             
AI Applications Institute,        ARPA:  J.Dalton%uk.ac.ed@nss.cs.ucl.ac.uk
Edinburgh University.             UUCP:  ...!ukc!ed.ac.uk!J.Dalton