1

Can someone explain to me why the code below throws an error (void-function fn)?

(let ((lexical-binding t)
      (fn (lambda (y) (+ y 4)))
      (x 4))
  (pcase x
    (10 (- x 2))
    (4 (fn x))))

and is there a way to fix it without defun'ing a function?

Muihlinn
  • 2,576
  • 1
  • 14
  • 22
Tohiko
  • 1,589
  • 1
  • 10
  • 22
  • 4
    `let` binds variables, not functions. So `fn` is a variable whose value is a function. You need to call it as `(funcall fn x)`. – Basil Jun 22 '20 at 09:30
  • Ah of course. Thanks! – Tohiko Jun 22 '20 at 09:36
  • @Basil: Please consider posting that answer as an answer. Comments can be deleted at any time. But maybe check also to see whether the question is a duplicate. Thx. – Drew Jun 22 '20 at 14:45
  • I have a feeling this question is a dup. I suggest searching for `void-function`... and maybe tag `[debugging]`. – Drew Jun 22 '20 at 14:48
  • @Drew I'm also pretty sure it's a duplicate but I can't find the original. – Basil Jun 22 '20 at 15:05
  • I wasn't able to find the original either. But I recognize that the question is pretty basic so it's probably answered as part of other questions. – Tohiko Jun 22 '20 at 15:06
  • Basic, even super-basic questions are most welcome! It's good to avoid duplicate questions, to consolidate the Q&A together (for search etc., in particular). – Drew Jun 22 '20 at 22:11
  • @Drew I searched “Lisp-2” and found https://emacs.stackexchange.com/questions/28979/error-void-variable-on-function-name and https://emacs.stackexchange.com/questions/14747/how-to-pass-function-as-argument-in-elisp which answer the opposite question (I have a function and want to pass it around as a variable), but not this (I have a variable and want to call it as a function). While the core explanation is the same, the practical solution is different so they aren't adequate duplicates. If a duplicate exists, it doesn't have a detailed explanation. – Gilles 'SO- stop being evil' Jun 23 '20 at 15:25
  • @Gilles'SO-stopbeingevil': Thanks for checking. – Drew Jun 23 '20 at 15:57

1 Answers1

3

Emacs is a “Lisp-2”: functions and values have separate namespaces. A function definition (defun foo …) and a function call (foo …) use the function slot of the symbol foo. A variable assignment (setq foo …), a variable binding (let ((foo …)) …), and a variable reference x use the value slot of the symbol foo.

To call a function which is stored in the value slot of a symbol, use funcall.

(funcall fn x)

More generally, but infrequently, the argument to funcall can be any Lisp expression. funcall is an ordinary function.

Lisp functions take a list of arguments. Sometimes, in addition to calling a variable function, you need to call the function with a variable list of arguments. In this case, use apply instead of funcall. The last argument to apply is used as a list of remaining arguments.

In this particular case, where the code of the function is fully known, you can also use cl-flet from the CL library that is distributed with Emacs. This doesn't let you easily pass the function around, which may or may not be an issue in your real program.

(require 'cl-lib)
(let ((lexical-binding t)
      (x 4))
  (cl-flet ((fn (y) (+ y 4)))
    (pcase x
      (10 (- x 2))
      (4 (fn x)))))