[Lisp] confused about using `#'` with lambdas

I was doing the ETL exercise in common-lisp track

In short, I have

(let ((transformer #'(lambda ...
  (maphash transformer data)
  ...

And in experiments, I found it also works if I omit #' in the arg list.

The Functions chapter of Practical Common Lisp demonstrates using #' with lambdas.

In the REPL I see this,

  1. with a named function:

    CL-USER(1): (defun hi () 'hello)
    
    HI
    CL-USER(2): hi
    ...  The variable HI is unbound.
    
    CL-USER(3): #'hi
    
    #<FUNCTION HI>
    

    Here, #'hi gets me the function object.

  2. with an anonymous function

    CL-USER(1): (defparameter greet1 (lambda () 'hello))
    
    GREET1
    CL-USER(2): (defparameter greet2 #'(lambda () 'hello))
    
    GREET2
    CL-USER(3): greet1
    
    #<FUNCTION (LAMBDA ()) {536DDC2B}>
    CL-USER(4): greet2
    
    #<FUNCTION (LAMBDA ()) {536DDB9B}>
    

    greet1 and greet2 look like they contain the same kind of object.
    What’s really the difference here?

I’m not a Common Lisp expert and I’m also not a seasoned Lisp programmer, so I’m very happy to be corrected if I get things wrong, but this is my explanation to the best of my current knowledge and understanding:

To understand why Common Lisp has the '# expression it is helpful to know that Common Lisp is a so called Lisp-2, which means that in Common Lisp you can have a variable that refers to a function and a value in the same scope at the same time.

See this Stack Overflow thread for more information and additional reading material: clojure - What is the difference between Lisp-1 and Lisp-2? - Stack Overflow

This also means that calling the lambdas in your second example won’t work, because defparameter doesn’t define a function:

CL-USER: (greet1)

("undefined function")

CL-USER: (greet2)

("undefined function")

Now in your example, how do we tell Lisp that we want the function of the name hi? One way is to write (function hi) but because this is long, there is the possibility to abbreviate this with the '# notation (Sharpsign Single-Quote).

See the HyperSpec on this: CLHS: Section 2.4.8.2

Now why can you write a lambda expression with the #' syntax in front of it?
In Common Lisp there are two ways to use lambda:

  1. as a symbol
  2. as a macro

The “as a symbol” part basically means that if a compound form doesn’t start with a symbol but with an s-expression that starts with a lambda symbol (lambda expression), then this lambda expression will be called as a function, which I think is a complicated way of saying that you can write ((lambda (x y) (+ x y)) 2 3) and it will evaluate to 5. To learn more about this I recommend reading up about forms and the evaluation model here: CLHS: Section 3.1.2.1.2

Now to use a lambda expression in a place where Lisp expects a function you need to tell Lisp that the lambda should be treated as a function, which you would usually do by wrapping it in a (function) call. And we learned earlier that (function) is equivalent to '#.

From the HyperSpec:

    (lambda lambda-list [[declaration* | documentation]] form*)
 ==  (function (lambda lambda-list [[declaration* | documentation]] form*))
 ==  #'(lambda lambda-list [[declaration* | documentation]] form*)

Or asking lisp about it:

CL-USER: (macroexpand '(lambda () 'hello))

#'(LAMBDA () 'HELLO)

Quoting from Stack Overflow:

FUNCTION is a special operator. It expects a function name or a lambda expression. Thus the name or the lambda expression are not evaluated. In fact lambda expressions can’t be evaluated at all. Inside FUNCTION, the lambda expression is not a macro form and thus will not be expanded again. The purpose of FUNCTION is to return the corresponding function object which is denoted by the name or by the lambda expression. It returns the function object as a value. With this special operator one can access the function object from global functions and lexical functions.

The discussions why some people prefer '# to the macro sometimes go over my head (see comments here), but I think you can see both forms as equivalent for now. One thing to note is that the lambda macro was initially not part of Common Lisp, so some old books might always use the Sharpsign Single-Quote form just because of that. (eg. On Lisp)

Thanks @fap you did a great job of explaining it.

Personally I like the consistency of using #’ everywhere I am providing a function to as a parameter so I use them on lambda as well.

@glennj I believe this question is specifically about Common Lisp - I’m wondering if it should be tagged/categorized as such?

Recategorized. I’m not familiar with other Lisps, so I don’t know how universal this question is.

I did find a useful discussion about this topic: https://lispcookbook.github.io/cl-cookbook/functions.html

1 Like