I'm somewhat new to CL and currently trying to wrap my head around mapcan
, #'
, funcall
and closures.
Here is a closure, which applies a predicate to a number n and, if correct, returns (list n)
, else nil
:
(defun all-those (predicate)
(lambda (n)
(if (funcall predicate n) (list n))))
I understand that I need to call funcall
to turn this closure into a function. This works fine:
> (funcall (all-those #'evenp) 8)
(8)
Now I tried to pass the hereby created function as an argument to mapcan:
> (mapcan #'(funcall (all-those #'evenp)) '(1 2 3 4))
I get a compile-time-error: (FUNCALL (ALL-THOSE #'EVENP)) is not a legal function name
.
But it works if I omit #'
as well as funcall:
> (mapcan (all-those #'evenp) '(1 2 3 4))
(2 4)
Now I'm confused. It was my understanding that I need to sharp-quote a function when using mapcan
to follow the symbol's function binding (*) and that I need to call funcall
when "closing a closure".
Is it because #'
and funcall
are cancelling each other out or why do I have to omit both of them in the above example? Thank you in advance for any replies.
(*) I know that in this example I don't really have a symbol whose function binding can be followed. But if I use an anonymous function and mapcan
I still need to sharp-quote it: (mapcan #'(lambda ...
To mapcar, funcall, etc., you need to pass either a function object or a symbol. If you pass a symbol, then the symbol-function of the symbol is used as the function. If you pass a function object, then it is used as the function.
Your all-those function returns a function. That means that (mapcan (all-those …) …) is fine.
The sharp quote (#') is just shorthand for the function form. That is, #'foo is the same as (function foo):
So you only use #' or function with a function name. That means either a symbol (e.g., #'car) or a lambda expression (e.g., #'(lambda (x) x)). That means that the following doesn't work (or really make sense, even):
The documentation for mapcar, etc., says that its first argument is:
From the glossary:
So, you can pass a function directly to mapcar, funcall, etc., which is exactly what you're doing in:
You can also do: