Помогите с dynamic-wind и call/cc

У меня возникли проблемы с пониманием поведения следующей программы Scheme:

(define c
  (dynamic-wind
    (lambda () (display 'IN)(newline))
    (lambda () (call/cc (lambda (k)
                     (display 'X)(newline)
                     k)))
    (lambda () (display 'OUT)(newline))))

Как я понимаю, c будет привязан к продолжению, созданному прямо перед "(display 'X)".

Но использование c, кажется, изменяет себя! Определение выше выводит (как я и ожидал) IN, X и OUT:

IN
X
OUT

И это процедура:

#;2> c
#<procedure (a9869 . results1678)>

Теперь я ожидаю, что при повторном вызове будет напечатано X, а это не так!

#;3> (c)
IN
OUT

И теперь c больше не процедура, и второй вызов c не сработает!

#;4> c    ;; the REPL doesn't answer this, so there are no values returned
#;5> (c)

Error: call of non-procedure: #<unspecified>

        Call history:

        <syntax>            (c)
        <eval>              (c)    <--

Я ожидал, что каждый вызов (c) будет делать одно и то же — печатать IN, X и OUT. Что мне не хватает?


person josh    schedule 13.06.2010    source источник


Ответы (1)


Запуск этого в Racket немного полезнее:

-> (define c
     (dynamic-wind
       (lambda () (display 'IN)(newline))
       (lambda () (call/cc (lambda (k)
                             (display 'X)(newline)
                             k)))
       (lambda () (display 'OUT)(newline))))
IN
X
OUT
-> c
#<continuation>
-> (c)
IN
OUT
define-values: context (defining "c") expected 1 value, received 0 values
-> (c 99)
IN
OUT
-> c
99

Обратите особое внимание на то, что c привязывается к значению продолжения, потому что ваше выражение возвращает k в качестве значения. И само k является продолжением выражения значения, что означает, что это продолжение ожидает получения значения, которое будет привязано к c. Поэтому для его вызова требуется одно значение, как требует Racket, что помогает прояснить, что здесь происходит (схема MIT, кажется, молча рассматривает это как неуказанное). В любом случае, применение этого продолжения к 99 означает, что возвращаемое значение этого выражения равно 99, поэтому вы возвращаетесь в контекст (вывод IN) и возвращаете 99 для привязки к c, а затем печатаете OUT в твой выход. Теперь вы изменили c, чтобы вместо этого было 99, поэтому вы не можете вызвать его в третий раз.

person Eli Barzilay    schedule 13.06.2010
comment
Ага, понятно! Теперь я чувствую, что это был действительно глупый вопрос, в конце концов. Большое спасибо! - person josh; 13.06.2010
comment
@Eli: так что вы не можете вызвать его в третий раз - если, конечно, вы всегда не вызываете (c c), который связывает c с продолжением процедуры, определяющей c... :-) - person Jay; 13.06.2010
comment
@Jay: ты прав, конечно. Я сосредоточился на настройке Джоша, за исключением того, что Racket требует отправки некоторого значения, поэтому использование c сделало бы его более запутанным. - person Eli Barzilay; 14.06.2010
comment
Эй, это забавно... Я определил c, как указано выше, а затем пять раз вызвал (c) на MzScheme v4.2.4, и это просто сработало. (?!) Не работает на Курице, Коварстве, Гамбите, Ипсилоне и SISC. - person Jay; 14.06.2010
comment
Вы имеете в виду (c) без аргументов? В 4.2.4 тоже должно было не получиться. - person Eli Barzilay; 14.06.2010