Can you clarify this further? To me a callback function is a lambda. It may or may not be a closure.
Can you clarify this further? To me a callback function is a lambda. It may or may not be a closure.
function foo(x) { return x + 1; }
function bar(f, y) { return f(y); }
// `foo` is a callback but neither a lambda nor a closure
bar(foo, 2);
edit: adding the missing the "b" in lambda foo = function (x) { return x + 1; }
is identical to function foo (x) { return x + 1; }
They are also closures. Since they don't refer to any outer variables, they are closures containing zero context variables. If foo were to refer to some other variable, the closure would contain one context variable.The only reason to distinguish between lambdas and closures is because some languages do not support closures (e.g. early versions of Emacs Lisp). Attempting to refer to other variables would always refer to a global variable with that name.
I'll concede that for JavaScript (and a few other languages); some languages don't treat all functions as just a lambda with a binding, though.
> They are also closures. Since they don't refer to any outer variables, they are closures containing zero context variables. If foo were to refer to some other variable, the closure would contain one context variable.
I'm not very keen on the definition of "closure" including functions that close over zero variables, because then "closure" becomes indistinguishable from "function", and the word is no longer useful. I might be wrong about the technical definition, but I feel like having a word for closures isn't very useful if it doesn't mean "closing over one or more variables".
> (lambda () (print "hi"))
(closure (t) nil (print "hi"))
> (let ((a 1) (b 2)) (lambda () (print "hi")))
(closure ((b . 2) (a . 1) t) nil (print "hi"))
> (let ((a 1)) (defun foo (x) (+ x 1)))
foo
> (symbol-function 'foo)
(closure ((a . 1) t) (x) (+ x 1))
> (defun bar (x) (+ x 1))
bar
> (symbol-function 'bar)
(closure (t) (x) (+ x 1))
So yes, every function is a closure.Every function isn't a closure. In particular, elisp lambdas aren't closures because elisp is dynamically bound - the variables are open, they are not closed over. Or with another perspective, the variables are bound in the global context. Either way, elisp closures aren't.
From emacs scratch buffer:
(setq f (let ((x 10))
(lambda ()
(progn
(setq x (+ x 1))
x))))
(funcall f)
11
(funcall f)
12
(setq x 20)
(funcall f)
21
This is because elisp is dynamically bound - it only has one environment (in this example), the global environment (leave aside buffer-local etc. for the moment).It doesn't matter if you try to create a new environment using a lambda, the same problem still occurs:
(setq g
(lambda (x)
(lambda ()
(progn
(setq x (+ x 1))
x))))
(setq f (funcall g 1))
(funcall f)
22 ;; or whatever you last assigned to x, + 1If you pass your examples to `(eval ... t)`, you'll see what I mean. Or run `(setq-local lexical-binding t)` before evaluating them in the scratch buffer.
> (setq g (lambda (x)
(lambda ()
(progn
(setq x (+ x 1))
x))))
(setq f (funcall g 1))
(funcall f)
2
> f
(closure ((x . 2) t) nil (progn (setq x (+ x 1)) x))
> (setq x 20)
20
> (funcall f)
3[0] https://developer.mozilla.org/en/docs/Web/JavaScript/Closure...
You can see this in Ruby where methods don't close over the environment, but blocks do, clearly Ruby methods aren't closures, not even when reïfied into a Method, whereas blocks are closures.
It's like code expecting rectangles wouldn't mind to get squares, but a code expecting squares will definitely do mind getting rectangles.
It is actually not that obvious since in OOP neither a square or a rectangle type is properly a subtype of the other. [0]
I understand how implementation-wise it could be convenient to treat a function as a closure. Although, I would prefer some other type, eg:
functoid := closure | function
[0] - https://stackoverflow.com/questions/1030521/is-deriving-squa...You might define the interface of a closure as `closure(f: Function, env: Mapping[str, Any])`, or in other words a closure is a function and a mapping of variable names to values. That mapping can be empty, but that's different than the different interface `not_a_closure(f: Function)`, which is incapable of closing over anything, including the empty set.
Pay attention to page 17 and subsequent pages, talking about variable binding in a closed or open context - this is the closing that closure refers to. Page 31 talks about closure in the context of a lambda.
-- only if lexical-binding is non-nil :)
What a surprise...
You're free to be as prejudiced as you want, but I gave an example of an actual implementation.
Regardless, though, I don't think what any one language calls something is going to go very far in convincing me. As for the Rust ad hominem, I've been specifically arguing against the terminology that Rust uses (i.e. all lambdas are called closures, and nothing is called lambdas) that is much more consistent to your viewpoint than mine, so I don't really see what point you're trying to make there, other than that you're as prejudiced against Rust as I am against Elisp. But that's fine though; people are free to like whichever languages they like, but I don't really think it's worth taking it personally when others disagree.
Most commonly a lambda is regarded as an anonymous function. [0] If you name it, it is no longer anonymous.
[0] - https://softwareengineering.stackexchange.com/questions/1307...