Создать экземпляр из замыкания - PullRequest
0 голосов
/ 03 ноября 2019

Я читаю пример 3.1 Назначение и местное состояние из 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

Практика с 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

Не сработало, как ожидалось, поэкспериментируйтев интерактивном режиме

Случай 1: вызвать make-withdraw напрямую и вернуть замыкание

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

Случай 2: присвоить его W1, но вернуть общую функцию, а не замыкание

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

Как можно создать экземпляр W1?

1 Ответ

1 голос
/ 03 ноября 2019
ELISP> (defvar W1 (funcall (withdraw 100)))

withdraw - это не make-withdraw - вы называли что-то еще.

ELISP> W1
(lambda ...)

И это что-то еще не было определено с lexical-binding активным, иначе вы бы увиделизакрытие.

Что касается этого ...

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

Вы назначаете функцию для переменной W1, что означает (как вы знаете из вашегодругие недавние вопросы здесь), что вы не можете использовать (W1 30), но вместо этого вам придется использовать (funcall W1 30)

...