Search code examples
clojurecommon-lisplisp-2

Calling a list of functions in Common Lisp


In Clojure, I can define a sequence of functions, then call them like they'd been any other value, as so:

(doseq [op [+ - * /]]
  (println (op 1 2 3 4)))

which produces the following output:

10
-8
24
1/24
nil

Trying to do the same in Common Lisp results in nothing but error:

(dolist (op '(+ - * /))
  (print (op 1 2 3 4))

; in: DOLIST (OP '(+ - * /))
;     (LET ((OP (TRULY-THE (MEMBER / * - +) (CAR #:N-LIST671))))
;       (SETQ #:N-LIST671 (CDR #:N-LIST671))
;       (TAGBODY (PRINT (OP 1 2 3 4))))
; 
; caught STYLE-WARNING:
;   The variable OP is defined but never used.

; in: DOLIST (OP '(+ - * /))
;     (OP 1 2 3 4)
; 
; caught STYLE-WARNING:
;   undefined function: OP
; 
; compilation unit finished
;   Undefined function:
;     OP
;   caught 2 STYLE-WARNING conditions

debugger invoked on a UNDEFINED-FUNCTION:
  The function COMMON-LISP-USER::OP is undefined.

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [ABORT] Exit debugger, returning to top level.

("undefined function")

Calling op as #'op didn't work for me either.

So is there a way to do this in CL?


Solution

  • Since the namespace for functions and the namespace for data are separate in LISP-2 (and hence in common-lisp), you need to use funcall when passing functions as parameters:

    (dolist (op '(+ - * /)) 
       (print (funcall op 1 2 3 4))))
    

    funcall function is an roughly equivalent of Clojure's apply, and will apply the op function to the provided parameters. In this case there's one more thing going on, since op is a symbol bound to a function, but funcall takes care of that.