4 ms·
Elisp disagrees: > (lambda () (print "hi")) (closure (t) nil (print "hi")) > (let ((a 1) (b 2)) (lambda () (print "hi"))) (closure ((b . 2) (a . 1) t)
by sillysaurus3 9y ago
Elisp disagrees:
> (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.
- kukx 9y agoIt depends on your definition of the closure. Example: "A closure is the combination of a function and the lexical environment within which that function was declared." [0] [0] https://developer.mozilla.org/en/docs/Web/JavaScript/Closures https://developer.mozilla.org/en/docs/Web/JavaScript/Closure...
- joshuamorton 9y agoA lexical environment being syonymous with "a set of 0 or more variables accessible from within the function, but not passed as arguments." The key piece of that being 0 or more. The null set is still a set.
- deleted 9y ago[deleted]
- deleted 9y ago[deleted]
- kukx 9y agoI do not think it is useful to interpret it as 0 or more. To me it only make sense to assume 1 or more. Otherwise you could say that the programming language that do not support closing variables, has nonetheless closures, as according to that notion every function is a closure that closes nothing.
- TeMPOraL 9y agoI think this is a rectangle/square problem. When you say you accept/return a closure, you probably mean a "function + lexical scope of 0 or more variables". You can still refer to "non-closures" as functions, though. It's like code expecting rectangles wouldn't mind to get squares, but a code expecting squares will definitely do mind getting rectangles.
- kukx 9y ago>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-square-from-rectangle-a-violation-of-liskovs-substitution-principle https://stackoverflow.com/questions/1030521/is-deriving-squa...
- irishsultan 9y agoThe key difference here is whether the language allows closure over the lexical environment, not whether the lexical environment contains anything used. 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.
- joshuamorton 9y agoWell no, because a closure is a function and an environment. A function closing over nothing is different than a function being unable to close over something. 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.
- agumonkey 9y agoI would prefer other sources of information. Like papers from 60s to 80s.
- barrkel 9y agohttp://repository.readscheme.org/ftp/papers/ai-lab-pubs/AIM-353.pdf http://repository.readscheme.org/ftp/papers/ai-lab-pubs/AIM-... (Lambda: The Ultimate Imperative, Steele & Sussman 1976) 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.
- barrkel 9y agoA closure is a combination of a function and the environment containing the variables it is bound to (closed over) rather than left open (like old LISPs, like elisp). 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, + 1
- sillysaurus3 9y agoYou're thinking of old elisp. Elisp hasn't been dynamically bound since around 2014. In modern elisp, every function is a closure. If 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
- saghm 9y agoNo offense, but I'm not going to base my understanding of how programming language terminology works on Elisp.
- sillysaurus3 9y ago> Rust enthusiast What a surprise... You're free to be as prejudiced as you want, but I gave an example of an actual implementation.
- saghm 9y agoCorrect me if I'm wrong, but isn't Elisp generally considered to be a rather poor dialect of Lisp? At the very least, there seems to be a desire in at least part of the Emacs community (i.e. the one place where Elisp is actually used) to replace it with Guile, which I can only assume is due to it being a superior language. 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.
- lispm 9y agoElisp is not to be replaced with Guile. That's a myth.
- hollerith 9y ago>So yes, every function is a closure [in Elisp]. -- only if lexical-binding is non-nil :)