Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why must I funcall a function returned from another?

Why doesn't this work?

( ((lambda () (lambda (x) (funcall #'1+ x)))) 2)
 ; yields Compile-time error: illegal function call

I ran into a situation like this and it later turned out that a funcall fixes it, i.e.

(funcall ((lambda () (lambda (x) (funcall #'1+ x)))) 2) ; => 3

I'm confused because it seems like the first one should work, because I actually have a function I'm calling, not just a symbol that may belong to either namespace (i.e. (type-of ((lambda () #'1+))) ; => FUNCTION). I thought it would be kind of like how you don't need to funcall a lambda for example, e.g.((lambda (x) x) :HI) ; => :HI. What am I missing?

like image 246
MasterMastic Avatar asked Dec 18 '22 17:12

MasterMastic


1 Answers

Common Lisp uses the word form for everything which can be evaluated. A form is either

  • a symbol like foo
  • a compound form, a list, see below
  • or a self-evaluating object (like numbers, characters, arrays, strings, ...).

A compound form is either

  • a special form (<special-operator> ...)
  • a lambda form like (lambda (...) ...)
  • a macro form (<macroname> ...)
  • or a function form (<functionname> ...).

Above is the set of compound forms. The ANSI Common Lisp specification provides no way to add a new type of forms or a different syntax. The interface of what forms the functions like EVAL or COMPILE accept is not extensible.

So something like

(((lambda (foo)
    (lambda (bar)
      (list foo bar)))
  1)
 2)

is not valid Common Lisp. This is not meaningful in Common Lisp:

( <not a lambda form,
   not a special operator,
   not a macro name
   and not a function name>
2)

Note that Common Lisp allows lambda forms, special operators, macro names and function names as the first element in a compound form. But it does not allow variables and it does not allow other compound forms as the first element in a compound form.

Means this is not meaningful in Common Lisp:

( <a function form> 2)

Thus ((foo 1) 2) or (((foo 1) 2) 3) or ((((foo 1) 2) 3) 4) or (((((foo 1) 2) 3) 4) 5) is not legal in Common Lisp. You get the idea. To call function objects returned from function calls, we have to use (funcall (foo ...) ...). This makes calling returned function objects more obvious than just ((foo ...) ...).

Let's praise the designers of Common Lisp for this feature. Otherwise I might have to look at possibly meaningful code beginning with

(((((((((((( .....

and it would be very hard to figure out what it does. Basically that would be write-only code.

Your question:

Why must I funcall a function returned from another?

The short answer: because the syntax does not allow other ways, in Common Lisp.

like image 67
Rainer Joswig Avatar answered Feb 12 '23 23:02

Rainer Joswig