Does (function) serve any purpose in Emacs?

2019-04-07 08:51发布

问题:

From the documentation of the function form:

Like `quote', but preferred for objects which are functions. In byte compilation, `function' causes its argument to be compiled. `quote' cannot do that.

So one would do #'(lambda ...) to enable byte compilation of the lambda form.

On the other hand, as mentioned in the manual, That is no longer necessary.

The lambda form has one other effect: it tells the Emacs evaluator and byte-compiler that its argument is a function, by using function as a subroutine.
[...] The following forms are all equivalent:

(lambda (x) (* x x)) 
(function (lambda (x) (* x x))) 
#'(lambda (x) (* x x))

This renders the function form useless in this case.

Is there any other situation where the function form would have been useful?
Is there any case when its presence is neither unnecessary nor identical to quote?

回答1:

#' (aka function) is used internally by lambda, since lambda is defined as a macro that wraps itself in a function. But other than that, you indeed can write pretty much any Elisp code without using #'. There is one other subtlety, tho: if you write #'foo you tell Emacs that you think foo is the name of a function, so recent versions of the byte-compiler will then warn if foo is not a known function (just like they've been warning about calls to (foo ...) for many years already).

As pointed out by @Bruce, the use of #'foo instead of 'foo also makes a real difference for functions defined locally via cl-flet or cl-labels: in that case #'foo refers to the locally defined function, whereas 'foo will simply refer to the foo symbol, which is not actually related to the local function definition and may hence by unbound or bound to another function:

(cl-flet ((a () 1)) (list 'a (functionp 'a) #'a))

returns

(a nil (lambda nil 1))


回答2:

lambda is a macro. It has to be expanded and it is expanded every time. Like this:

(lambda (x) x) -> (function (lambda (x) x)) ; #'(lambda (x) x)

function is a special operator. In fact, it treats lambda forms specially, otherwise we would never be able to expand lambda macro:

(lambda (x) x) ->
  (function (lambda (x) x)) ->
    (function (function (lambda (x) x))) ->
      ...

function looks at its argument and if it is a lambda form, it compiles the function. If its argument is a symbol, then it searches for compiled function associated with the symbol.

So, we see now, that function (like quote) does not evaluate its argument. It must have special behavior, thus it is a special operator.



回答3:

So one would do #'(lambda ...) to enable byte compilation of the lambda form.

On the other hand, as mentioned in the manual, That is no longer necessary.

It's no longer necessary for the programmer to write (function (lambda …)) (or the shorthand #'(lambda …), because (lambda …) expands to (function (lambda …)). Other answers have explained that very well. You first cite the documentation for function:

From the documentation of the function form:

Like quote, but preferred for objects which are functions. In byte compilation, function causes its argument to be compiled. quote cannot do that.

Thus, the documentation of function isn't addressing the difference between

  • (function (lambda …)) and
  • (lambda …),

but rather between

  • (quote (lambda …)) and
  • (function (lambda …)).

In most modern Lisps (Common Lisp, Scheme, etc.), the form (quote (lambda …)), or simply '(lambda …)) is just a list, and it's not something that can be invoked. E.g., in SBCL:

* (funcall '(lambda () 42))
; debugger invoked on a TYPE-ERROR in thread #<THREAD "initial thread" RUNNING {1002978E71}>:
;  The value (LAMBDA () 42) is not of type (OR FUNCTION SYMBOL).

However, in Emacs Lisp, you can invoke a list:

(funcall '(lambda () 42))
;=> 42

In asking whether function serves any purpose, we have to ask "what can we do without it," or "what alternative is there?" We can't respond that that "we would just write (lambda …)," because, as others have pointed out, that just expands to (function (lambda …)). If we don't have function, we can still use quote. We could still write a lambda macro that expands to (quote (lambda …)), and thus write (funcall (lambda …)), and the code would look the same. The question is, "what's the difference?" The difference is that in a quote-based version, we're passing literal lists around, and these can't get compiled to functions because we still have to be able to do list-like things with them (e.g., take their car and cdr). This is where function is useful, whether we write it ourselves, or depend on a macro to use it in an expansion. It gives a way of writing function objects instead of lists.



标签: emacs lisp elisp