Что возвращает продолжение в схеме?
Я наткнулся на то, чего не могу понять.
#lang scheme
(define cc #f)
(define (val!)
(call/cc
(lambda (k)
(set! cc k)
0)))
(* 10 (val!))
(cc 100)
Все идет нормально; продолжение (* 10 [])
хранится в cc
и если мы позвоним (cc 100)
мы видим 1000
в REPL, как и ожидалось.
Но затем я попытался определить переменную, которая будет результатом выполнения продолжения:
(define x (cc 20))
я вижу 200
в результате в REPL, но x
не определяется
Сохранено ли продолжение в cc
включить его возвращение, так что вызов define
никогда не возвращается, и вместо этого оценка является результатом (* 10 val)
? Что здесь происходит?
2 ответа
В чем дело?
Есть два типа продолжений.
Продолжение, созданное call/cc
никогда не возвращает значение своему вызывающему См . Ответ Уилла Несса, чтобы узнать больше.
Но продолжения произведены call-with-composable-continuation
являются составными продолжениями, которые возвращают значения.
Решение
Если вы хотите, чтобы продолжение возвращало значение вызывающей стороне, вы должны использовать составное продолжение, настроив приглашение и используя call-with-composable-continuation
,
Вы можете определить вид приглашения:
(define my-prompt
(make-continuation-prompt-tag 'my-prompt))
И используйте подсказку в call-with-composable-continuation
указать, что вы хотите захватить только продолжение, начиная с приглашения.
(define cc #f)
(define (val!)
(call-with-composable-continuation
(lambda (k)
(set! cc k)
0)
my-prompt))
Затем вам нужно просто поставить подсказку, где вы хотите, чтобы продолжение продолжалось, прежде чем вы позвоните val!
чтобы сохранить это.
;; the prompt specifies that it's `(* 10 [])`, and not something larger
(call-with-continuation-prompt
(λ () (* 10 (val!)))
my-prompt)
Затем, поскольку у этого продолжения есть четкий "конец", определенный приглашением, он может вернуть значение, когда достигнет этого конца.
(define x (cc 20))
; defines x as 200
Читайте также: Что такое "приглашение к продолжению"?
Он ничего не возвращает, потому что не возвращает. (cc 20)
, как только (cc 100)
, не возвращает значение вызывающей стороне. cc
это не функция, это продолжение - она сама запоминает, куда возвращать / "кормить" свое значение.
(define x (cc 20))
означает, примерно, в псевдокоде,
(let ([val (cc 20)])
(primitive-define-top-level-var! "x" val))
но (cc 20)
обходит настройку val
и используя его для определения x
и возвращается непосредственно на верхний уровень, как это было сделано в исходном захваченном продолжении.
Сохранено ли продолжение в
cc
включите его возвращение [ "destination" - wn], чтобы вызовdefine
никогда не возвращается, и вместо этого оценка является результатом(* 10 val)
?
Да.
Что здесь происходит?
Именно это.
редактировать:
Загрузка следующего в DrRacket,
#lang scheme
(define cc #f)
(define (val!)
(call/cc
(lambda (k)
(set! cc k)
0)))
(* 10 (val!))
(cc 100)
(display "Good!\n")
(define x (cc 20))
(display "Shucks!\n")
Я даже получаю сообщение об ошибке, объясняющее, что происходит:
Язык: схема, с отладкой; ограничение памяти: 128 МБ.
0
1000
Хорошо!
200
define-values: пропущенное определение переменной;
не может продолжаться без определения переменной
переменная: х
в модуле: 'анонимный модуль
>