Поскольку первая причина также может быть выполнена с помощью процедуры значений, а вторая - case-lambda, я не понимаю преимущества использования стиля передачи продолжения.
...за исключением того, что определение values
указывает, что оно вызывает его продолжение с несколькими аргументами.
Мой любимый пример проблемы, где стиль передачи продолжения полезен, - написание сопоставителей шаблонов.Это своего рода макрос, который похож на case
на стероидах;он принимает значение и пытается сопоставить свою структуру с последовательностью шаблонов, построенных из пар, символов (обозначающих переменные) и не символьных атомов (обозначающих значения).Если совпадение успешно, то оно связывает идентификаторы в шаблоне с соответствующими частями значения и выполняет последовательных для этого шаблона.Если это не удается, тогда он пытается следующий шаблон.
Довольно просто написать этот вид макроса в форме стиля передачи продолжения, используя два разных продолжения, чтобы представить «что делать, если совпадение успешно» (продолжение успеха) и «что делать, если совпадение не удается» (продолжение неудачи).
Возьмите этот (упрощенный) фрагмент макроса сопоставления с образцом, который я однажды написал (извиняюсь, если вы не знаете синтаксис-регистр или синтаксис-правила; и, поскольку я адаптировал его на лету, я уверен, что надеюсьтоже работает!).Я собираюсь сосредоточиться на правиле, которое соответствует шаблону пары.Это образец, который состоит из пары двух рисунков, рисунка головы и рисунка хвоста;он соответствует парам, голова которых соответствует шаблону головы, а хвост соответствует шаблону хвоста.
;;;
;;; Outer "driver" macro; the meat is in pmatch-expand-pattern.
;;;
(define-syntax pmatch
(syntax-rules ()
((pmatch value-expr (pattern . exprs) . clauses)
(let* ((value value-expr)
(try-next-clause
(lambda () (pmatch value . clauses))))
(pmatch-expand-pattern pattern
value
;; success-k
(begin . exprs)
;; failure-k
(try-next-clause))))))
(define-syntax pmatch-expand-pattern
(lambda (stx)
(syntax-case stx ()
;; Cases for constants and quoted symbols omitted, but they're trivial.
;; Match a pair pattern. Note that failure-k is expanded three times;
;; that's why pmatch encapsulates its expansion inside a thunk!
((pmatch-expand-pattern (head-pat . tail-pat) value success-k failure-k)
(syntax
(if (pair? value)
(pmatch-expand-pattern head-pat
(car value)
;; If we successfully match the head, then
;; the success continuation is a recursive
;; attempt to match the tail...
(pmatch-expand-pattern tail-pat
(cdr value)
success-k
failure-k)
failure-k))
failure-k))
;; Match an identifier pattern. Always succeeds, binds identifier
;; to value
((pmatch-expand-pattern identifier value success-k failure-k)
(identifier? (syntax identifier))
(syntax (let ((identifier value)) success-k)))
)))
Обратите внимание на подчиненные формы success-k и fail-k в выражениях макросов pmatch-expand-pattern
.Они представляют выражения, которые используются в качестве «продолжения» в несколько упрощенном выражении для сопоставления с образцом.Продолжение успеха используется, когда рассматриваемый шаблон соответствует рассматриваемому значению;продолжение сбоя используется, когда это не так.Продолжение успеха, в зависимости от того, соответствовали ли мы всем текущему шаблону верхнего уровня, является либо выражением, которое будет соответствовать остальной части шаблона, либо результатом, которое мы выполняем, когда шаблон завершает сопоставление.Продолжения сбоев используются, когда шаблон не соответствует, чтобы вернуться к следующей точке выбора.
Как я уже упоминал, термин "продолжение" используется немного свободно в приведенном выше коде, так как мыВы используете выражения в качестве продолжения.Но это всего лишь деталь о том, как реализовать это как макрос - алгоритм может быть реализован исключительно во время выполнения с использованием реальных процедур в качестве продолжения.(Кроме того, try-next-clause
процедуры являются продолжениями в буквальном смысле.)