Search code examples
emacslispelisp

Elisp: Bind a lambda in a Let and execute it


I am attempting to understand the lambda notion found within Emacs Lisp.

In ielm, executing:

((lambda (x) (* x x)) 5)

gives us 25, and

(let ((x 4)) (* x x))

gives us 16. However when I do:

(let ((f (lambda (x) (* x x)))) (f 7))

it does not give me 49, but instead informs me:

*** Eval error ***  Symbol's function definition is void: f

Don't know why, I am sure the syntax is right and f is defined in the let?

Using cl-flet to define let-ed function

We can actually do this without using funcall. The cl module includes standard functions from Common Lisp. We first import it:

(require 'cl)

Thereafter we can use cl-flet to define our function:

(cl-flet ((f (x) (* x x)))
  (f 7))

Solution

  • I'd be surprised if this isn't a duplicate, but I can't find it readily here on Stack Overflow. In "Lisp-2" languages (e.g., Emacs Lisp and Common Lisp), there are separate namespaces for functions and variables. A function call looks like either:

    ((lambda ...) ...) ; call the lambda function
    

    or

    (f ...) ; call the function binding of f
    

    If you want to call the function that is the value of a variable, then you need to use funcall or apply:

    (apply f ...)
    
    (funcall f ...)
    

    The difference between apply and funcall is well documented in other places, but the quick difference is that apply expects an argument list (in some Lisps, a "spreadable argument list"), whereas funcall takes the arguments directly. E.g.,

    (let ((f (lambda (a b) (+ a b))))
      (funcall f 1 2)      ; arguments directly
      (apply f '(1 2)))    ; arguments in a list
    

    In a "Lisp-1", (like Scheme), you don't need funcall, since there's only one space for bindings. In Scheme you can do:

    (let ((f (lambda (a b) (+ a b))))
      (f 1 2))
    

    The difference between Lisp-1 and Lisp-2 languages is described more in What is the difference between Lisp-1 and Lisp-2?. The big difference is when the system sees a function call, how it figures out what function to call. In a Lisp-1, variables have values, and that's all. So when the system sees something like:

    (f ...)
    

    f is a variable, and the only possible thing to call is the value of f. In a Lisp-2, the systems tries to call the function value of f, which doesn't have to have anything do with the value of the variable f. That can be a bit confusing at first, but it's actually pretty handy in many cases, because it makes it harder to accidentally obscure functions with common names. E.g., in a Lisp-1, you'll see lots of people use lst as an argument name instead of list, because if they named the argument list, then they couldn't use the (standard) function list within the function.