Emacs lisp: why does this sexp throw an invalid function error?

Sexual question in question

(((lambda (b) (lambda (a) (+ ba))) 3) 5) 

which, it seems to me, should be evaluated as 8 , and in other lisps (for example, Racket), but in elisp it generates this error instead:

 Debugger entered--Lisp error: (invalid-function ((lambda (b) (lambda (a) (+ ba))) 3)) 

I think that

 ((lambda (b) (lambda (a) (+ ba))) 3) 

Not a valid function. This seems wrong, because when I evaluate this expression, I get

 (lambda (a) (+ ba)) 

which looks like a valid function to me. Does anyone know why this is happening? Is this related to dynamic reach?

+7
source share
4 answers

There are two problems here. The first is a syntax issue, as the other answers pointed out. The second question that is mentioned in the question is a question of problems.

Syntax Release

In Emacs Lisp (and the other Lisps in the Lisp-2 family), a function call looks like (f args...) where f is either the character that has the value of the function or the lambda expression. For instance,

 (list 1 2 3) => (1 2 3) 

because list has a binding function. Besides,

 ((lambda (xy) (list xxyy)) 1 2) => (1 1 2 2) 

because (lambda (xy) (list xxyy)) is a lambda expression. However, what you cannot do is that value, which is a function.

 (let ((id (lambda (x) x))) (id 3)) 

signals a Lisp error: (void-function id) . But we can call function values ​​using funcall :

 (let ((id (lambda (x) x))) (funcall id 3)) => 3 

Note. This is a pretty good way to look at it, but it's actually a bit more complicated. See 9.2 Form Views in the manual for details and esoteric bits, such as functional indirection.

So now we can solve the syntax problem. The source code reformatted the bit to indicate which functions receive which arguments:

 (((lambda (b) (lambda (a) (+ ba))) 3) 5) 

As I understand it, the goal is to first call (lambda (b) ...) with argument 3 to return an anonymous function, (lambda (a) ...) . In Emacs Lisp, this will be:

 ((lambda (b) (lambda (a) (+ ba))) 3) => (lambda (a) (+ ba)) 

Now you also want to call the returned anonymous function with 5 . We use funcall for this:

 (funcall ((lambda (b) (lambda (a) (+ ba))) 3) 5) 

The problem of determining the area

Disappointingly, this code creates a Lisp error: (void-variable b) . It is here that we are finally confronted with the problem of dynamic and lexical coverage. Since the variable b was linked dynamically, its value is not stored in the anonymous function (lambda (a) (+ ba)) . We can verify that this happens by surrounding the whole form in that b connects and sees what happens:

 (let ((b 100)) (funcall ((lambda (b) (lambda (a) (+ ba))) 3) 5)) => 105 

I don't really like the hacker Emacs Lisp, so I'm not sure of the best way to get lexical closures in Emacs. I read that Emacs 24 has one, but I'm still here 23. Based on this answer , we can use lexical-let to get the desired results:

 (funcall ((lambda (b) (lexical-let ((bb)) (lambda (a) (+ ba)))) 3) 5) => 8 

lexical-let sets the required lexical binding so that the anonymous function (lambda (a) ...) has 3 in it. More specifically, we introduced the lexical binding of b , and this is due to the fact that references to vocabulary that (lambda (a) …) refer. In fact, if we look at the returned anonymous function now, this is not easy (lambda (a) (+ ba)) , but it prints in a more complex (and less useful) way:

 ((lambda (b) (lexical-let ((bb)) (lambda (a) (+ ba)))) 3) => (lambda (&rest --cl-rest--) (apply (lambda (G27322 a) (+ ... a)) (quote --b--) --cl-rest--)) 

As an aside, it doesn't matter that the lexically related variable b has the same name as the dynamically linked b ; we could use (lexical-let ((cb)) ... (+ ca) ...) .

+14
source

Short answer: Lisp -1 vs. effect Lisp -2

A slightly longer answer: for an Emacs application, Lisp calls the function value of the first character in the list, but lambda returns just a simple function object. This means that you will need to use funcall for everything to work. funcall applies its second argument to the remaining arguments (such as apply , but the latter displays its last argument as a list).

 (funcall (lambda (a) (funcall (lambda (b) (+ ab)) 5)) 3) => 8 

Take a look at the emacs documentation (e.g. Ch f funcall ) for more information.

+3
source

car of (((lambda (b) (lambda (a) (+ ba))) 3) 5) not a character with a valid function definition, nor is it a lambda character, so it is not a valid function call.

+2
source

FWIW, another permutation would give you the following:

 ((lambda (b) ((lambda (a) (+ ba)) 3)) 5) => 8 

(but I don’t think what you were trying to do)

+1
source

Source: https://habr.com/ru/post/947277/


All Articles