I'm piqued by the code in this old answer explaining why sharp quote is needed, but what I don't understand is why funcall
seems to skip the usual scope rules.
(defun test () 'red)
(flet ((test () 'green))
(list (funcall 'test)
(funcall #'test))) => (red green)
Should I understand Common Lisp as having both "local" lexically scoped symbol bindings as set by let-family functions and globally scoped variables symbol bindings as set by de- family functions?
Common Lisp is assumed.
DEFUN and friends
DEFUN creates a global function binding, which can retrieved via symbols.
(defun foo () 'foo)
Above we have a function FOO.
Let's call it:
(funcall (function foo)) ; no lexical bound function available, so it uses
; the symbol's binding
or
(funcall (symbol-function 'foo))
or
(funcall 'foo)
or
(foo)
All above access the same function.
Note: above shows that (foo)
and (funcall 'foo)
calls the same function. There is an exception: a file compiler may assume that a function FOO
does not change. This allows a Lisp compiler to inline code or to compile to faster function calling code. Calling the function via the symbol as in (funcall 'foo)
always results in a call to the current and latest binding - thus a lookup via the symbol is always needed.
FLET and LABELS
FLET and LABELS create lexically scoped function bindings. FUNCTION
can reference such a binding. Note that these bindings can't be accessed via symbols at runtime. There are only two ways:
Since both are using static lexical references, there is no lookup at runtime via symbols or similar. That means, symbols are not involved at runtime with lexical functions - they are only visible in the source code.
(flet ((foo () 'bar)) ; <- local lexical scope, function binding
(foo) ; calls the lexical bound function foo
or
(funcall (function foo)) ; calls the lexical bound function foo
but
(funcall (symbol-function 'foo)) ; calls the symbol's binding,
; not the lexical binding
and
(funcall 'foo) ; calls the symbol's binding
; not the lexical binding
)
This doesn't actually have much to do with funcall
, but rather the difference between quote
and function
. Try it again without the funcall
:
(defun test () 'red)
(flet ((test () 'green))
(list 'test #'test)) => (TEST #<FUNCTION (FLET TEST) {C14D26D}>)
One of them is a symbol, and the other is a function object - the
(lexically bound) function value of test
. As you can see, quote
returns its argument (without evaluating it) - that's where the lexical scope is ignored.
Once you understand this difference, it should be fairly clear why funcall
behaves as it does in this example (at least, if you understand how funcall operates on symbols - see the hyperspec entry).
The funcall
function takes a function designator (a function object or a symbol). With #'foo
you retrieve the function object bound to foo
, in the lexical context this is evaluated. With 'foo
, you create the symbol foo.
When funcall
then maps the function designator to a function, it's either simply the identity (if you pass a function object, this is used) or has to be looked up in the global environment.