Search code examples
elispsicp

Create an instance from a closure


I am reading the example 3.1Assignment and Local State from SICP

#+begin_src scheme 
(define (make-withdraw balance)
  (lambda (amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount))
               balance)
        "Insufficient funds")))
(define W1 (make-withdraw 100))
(W1 50)
(W1 30)
#+end_src

#+RESULTS:
: 20

Practice with elisp

#+begin_src emacs-lisp lexical t
(defun make-withdraw(balance)
  (lambda (amount)
    (if (>= balance amount)
        (progn (setq balance (- balance amount))
               balance)
        "Insufficient funds")))
(make-withdraw 10)
(defvar W1 (make-withdraw 100))
(funcall (W1 30))
#+end_src

#+RESULTS:
: W1

Did not work as expected, experiment it interactively

Case 1: call make-withdraw directly and return a closure

;; lexical-binding t 
ELISP> (make-withdraw 100)
(closure
 ((balance . 100)
  t)
 (amount)
 (if
     (>= balance amount)
     (progn
       (setq balance
             (- balance amount))
       balance)
   "Insufficient funds"))

Case 2: Assign it to a W1, yet return a common function rather than a closure

ELISP> (defvar W1 (funcall (withdraw 100)))
W1
ELISP> W1
(lambda
  (amount)
  (if
      (>= balance amount)
      (progn
        (setq balance
              (- balance amount))
        balance)
    "Insufficient funds"))

How could create an instance W1?


Solution

  • ELISP> (defvar W1 (funcall (withdraw 100)))
    

    withdraw is not make-withdraw -- you've called something else.

    ELISP> W1
    (lambda ...)
    

    And that something else was not defined with lexical-binding active, otherwise you would be seeing a closure.

    As for this...

    (make-withdraw 10)
    (defvar W1 (make-withdraw 100))
    (funcall (W1 30))
    

    You're assigning a function to a variable W1 which means (as you know from your other recent questions here) that you cannot use (W1 30) but would instead have to use (funcall W1 30)