Why sharp quote lambda expressions?
Asked Answered
P

4

22

It is a technique used frequently in On Lisp, which is on Common Lisp:

> (mapcar #'(lambda (x) (+ x 10))
         '(1 2 3))
(11 12 13)

Why is sharp-quote needed or even possible? lambda expressions return function objects, and sharp quoting returns function objects from names. I also have heard contradictory information on whether lambda expressions are names - in particular On Lisp contradicts the standard, but his code seems to work which also contradicts the standard.

In elisp it seems it's not needed at all. To my surprise this included no discussion of lexical scope, so it's unclear why it should be different from Common Lisp at all. But this answer says that unquoted lambda expressions make no sense whatsoever, hence, ironically, it was possible to introduce unquoted lambda expressions as syntactic sugar for quoted ones. But this contradicts the elisp manual's claim that "In Emacs Lisp, such a list is a valid expression which evaluates to a function object."

This question is tagged both common- and e- lisp because I'm trying to understand the theoretical model underlying both, and learn them by learning their differences. (More practically I'm trying to learn elisp but found lots of good resources on Common Lisp so am caught up learning both).

Peruse answered 30/3, 2015 at 3:33 Comment(1)
See also the Elisp Reference manual which implies that function quoting helps the byte compiler identify pieces of code which should be compiled. But I agree that this should probably be explained in more detail by somebody with the proper insight.Sayre
D
29

Common Lisp assumed.

Why is sharp-quote needed or even possible?

If you want to compute a function object from a function name (especially if you want to refer to a lexical binding) or a lambda expression, you need the special operator FUNCTION, or shorter #'.

lambda expressions return function objects,

They don't. Lambda expressions can't even be evaluated.

In Common Lisp it looks like (lambda () nil) can be evaluated. But it can't.

Sometime after CLtL1 a macro LAMBDA has been added that expands it into a (FUNCTION ...) expression. This macro saves some typing and let's code look a bit more like Scheme. Let's check this LAMBDA macro:

CL-USER 17 > (macroexpand-1 '(lambda () ()))  ; not a lambda expression
(FUNCTION 
  (LAMBDA NIL NIL)                            ; <- this is a lambda expression
)
T

This means that the following happens if you evaluate (lambda () ()):

  • LAMBDA is a macro. Thus the form gets expanded to (function (lambda () ())).
  • (function (lambda () ())) -> FUNCTION is a special operator. It returns a function object
  • ->

If you write: #'(lambda () ()) or (function (lambda () ())), then you'll skip the macro expansion.

Okay, now for something strange:

CL-USER 18 > (lambda () ())   ; <- this is not a lambda expression.
                              ;    it's a macro form, see above 
#<anonymous interpreted function 40600009FC>

Because above is a macro form, it will be expanded first and then it can be evaluated.

CL-USER 19 > (function          ; <- this is a special form
              (lambda () ())    ; <- this is a lambda expression
              )
#<anonymous interpreted function 4060000C0C>

Here it really is a lambda expression. Inside the special operator FUNCTION the form will not be macro expanded or similar.

CL-USER 20 > (                  ; <- this is a function call
              (lambda () ())    ; <- this is a lambda expression
              )

Above again, shows a lambda expression. Where ((function (lambda () ()))) is not valid Common Lisp. In the function position of a function call, Common Lisp expects either a function name or a lambda expression, but not something which needs to be evaluated.

and sharp quoting returns function objects from names.

FUNCTION, for which #' is a short notation, returns function objects from function names or lambda expressions.

See the documentation: FUNCTION.

I also have heard contradictory information on whether lambda expressions are names - in particular On Lisp contradicts the standard, but his code seems to work which also contradicts the standard.

If you want to hear the last word, read the ANSI CL standard. Alternatively use the Common Lisp Hyperspec, which is web-readable and derived from the standard.

On Lisp is definitely useful to read, but it might not follow the wording or semantics of ANSI CL in full detail. On Lisp was published after CLtL2, but before ANSI CL.

What does it mean practically when writing code?

If you are old, like me, and CLtL1 was the last thing you read of Common Lisp then write code like:

(mapcar #'(lambda (x) (* x x)) '(1 2 3))

If you are even older and grew up with Scheme, or are younger and have read the Common Lisp Hyperspec, then you might want to write:

(mapcar (lambda (x) (* x x)) '(1 2 3))

But for all, when it comes to function names, this is the default to write:

(mapcar #'sin '(1 2 3))
Dis answered 30/3, 2015 at 13:4 Comment(1)
Is (lambda ...) treated as a lambda expression and not macro ONLY in (function ...) special form? Because I don't know I keep using #'.Hosea
C
8

In short, you don't have to sharp-quote lambda because it is a macro that expands to (function (lambda ...)), and it is function that does all the magic.

The only sense in which function is not necessary is that you don't have to type it yourself. It is function, not lambda, that is the fundamental operator. Lambda expressions themselves are just ordinary lists (which function knows how to turn into function objects), and lambda is just an ordinary macro. So you've got things rather backwards: that lambda expressions return function objects does not obviate function because lambda is explained in terms of function.

An additional wrinkle is that in Emacs Lisp, lists that start with lambda can be treated as functions directly, without going through function. This is not the case in CL (although an explicit conversion is available in the form of (coerce some-list 'function)).

Centesimo answered 30/3, 2015 at 5:19 Comment(0)
L
6

It all has to do with history. (lambda ...) is just syntactic sugar for #'(lambda ..). Earlier versions of Common Lisp didn't have lambda defined as a macro. Eg. if you read Peter Norvigs essay about Quines (PD, page2) you see he explicitly states you need to create such macro as follows:

(defmacro lambda (args &body body)
  "Allow (lambda (x) ...) instead of #'(lambda (x) ...)"
  `#'(lambda ,args .,body))

Thus when writing (lambda ...) today a standard macro rewrites it to #'(lambda ...).

On Lisp is an old book and it may have been first published before the macro became standard. It also may be that Paul Graham is used to write #'(lambda ...) and has stuck with it.

I've seen that later editions of computer books often change as little as possible when conforming to a newer standard. I'm not sure that is a good thing.

Lindholm answered 30/3, 2015 at 12:33 Comment(1)
Just a clarification of what you are saying. I was studying this (a bit late). The (lambda ...) MACRO is just syntactic sugar, not any (lambda ...). The reason I say this is: You can do (function (lambda () 3)) but not (function #'(lambda () 3)) because (lambda () 3)) is a lambda expression, not a macro here. (See Rainer's post which helped me understand this).Hosea
O
2

The function keyword appears to have had different meanings in different Lisp languages.

In LISP 1.5, it was used to create a closure, using the funarg device. Reference: http://c2.com/cgi/wiki?DynamicClosure, and the LISP 1.5 Programmers Manual, Appendix B.

In MacLisp, it was used as a hint to the compiler to say that the lambda expression could be compiled as code. Reference: The Pitmanual, 7. Definitional Forms. It was not used to create closures; the *function special form did something similar. Reference The Pitmanual, 3. The Evaluator.

In Emacs Lisp, it is a hint to the compiler, and can also create lexical closures. Reference: Emacs Lisp Reference Manual, 12.7 Anonymous Functions.

Ophthalmoscopy answered 30/4, 2015 at 14:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.