4

I'm having trouble understanding the approach I need to take to fold over a list of functions and invoke them all with a particular argument.

Here is what I as assumed would work. I've tried various variations on it, using eval etc. Any pointers?

(mapcar (lambda (fn) (fn 'utf-8))
        (list #'set-terminal-coding-system
              #'set-keyboard-coding-system
              #'prefer-coding-system))

When I run this I just get "Symbol's function definition is void: fn".

EDIT | Ok, so this works, but it seems odd to need to use apply when the above example passes the functions with the #'function-name synax.

(mapcar (lambda (fn) (apply fn '(utf-8)))
        '(set-terminal-coding-system
          set-keyboard-coding-system
          prefer-coding-system))
d11wtq
  • 34,788
  • 19
  • 120
  • 195
  • Re: oddness, I don't find it any more odd than the dereferencing you have to do if you have the name of a variable as a symbol (or string) and want to access its value. – tripleee May 19 '13 at 18:55

2 Answers2

7

In Emacs lisp, symbols have separate value and function slots1.

Function arguments are passed in as the value of the argument's symbol, but when you evaluate (fn 'utf-8) you are using the fn symbol's function slot, which will not contain what you want (or in this instance, anything at all; hence the error "Symbol's function definition is void: fn").

To call a function held in a variable, you must therefore funcall or apply (or similar).

See also:

1 i.e. it is a so-called "lisp-2", as opposed to a "lisp-1" where there is a single name-space for both.

Community
  • 1
  • 1
phils
  • 71,335
  • 11
  • 153
  • 198
  • Thanks. So I knew about the namespace thing, though I assumed that since I was passing them in with the `#'function-name` syntax, the Lisp reader would know they were functions. When do the `#'syntax` come into play? Or is that only a Common Lisp thing? (I'm learning both at the same time). – d11wtq May 19 '13 at 12:11
  • Sorry, just found that section in the manual. So `#'name` is just a syntactical variation on `'quoted-name` to be used on functions. – d11wtq May 19 '13 at 12:14
  • 1
    That's correct, but you probably don't need to use it. `#'...` is short-hand for `(function ...)` which is simply a variant of `'...`/`(quote ...)` that also hints to the byte-compiler that it can compile the quoted form as a function. However in modern Emacs `(lambda ...)` is equivalent to `#'(lambda ...)`, so I believe there are extremely few situations in which you might need to be explicit. – phils May 19 '13 at 13:35
  • 1
    @d11wtq: It knows that they're functions, as you construct the list. It doesn't know that `fn` is a variable, rather than a function, that's what `apply` or `funcall` do. FWIW, `(funcall fn 'utf-8)` is probably more idiomatic than `(apply fn '(utf-8))` but they do the same thing, so... – Vatine May 22 '13 at 09:17
1

For side-effects, dash list library has function -each and its anaphoric counterpart --each:

(-each '(fn1 fn2 fn3) (lambda (x) (funcall x YOUR-ARGUMENT)))
(--each '(fn1 fn2 fn3) (funcall it YOUR-ARGUMENT))

If you want to collect results of these functions in a list, use -map instead, with arguments reversed:

(-map (lambda (x) (funcall x YOUR-ARGUMENT)) '(fn1 fn2 fn3))
(--map (funcall it YOUR-ARGUMENT) '(fn1 fn2 fn3))
Mirzhan Irkegulov
  • 17,660
  • 12
  • 105
  • 166