Hacker News new | past | comments | ask | show | jobs | submit login

A 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



You'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




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: