Опытный интриган, летч и коварство
Несколько вопросов здесь относительно letcc
это используется в Закаленном Schemer.
(define (intersect-all sets)
(letcc hop
(letrec
((A (lambda (sets)
(cond
((null? (car sets)) (hop '())
((null? (cdr sets)) (car sets))
(else
(intersect (car sets)
(A (cdr sets)))))))
; definition of intersect removed for brevity
(cond
((null? sets) '())
(else (A sets))))))
Я думаю, что я понимаю, что
letcc
достигает, и это в основном что-то вродеcatch
а такжеthrow
в ruby (и, по-видимому, CL), что означает, что весь блок кода может быть обрезан путем вызова любого из названныхletcc
является. Это похоже на наименее "функциональную" вещь, с которой я сталкивался в этой короткой серии книг, и это заставляет меня чувствовать себя немного неохотно, поскольку я хочу выучить хороший функциональный стиль. Я просто недоразумениеletcc
Или это не действительно концепция функционального программирования и существует только для повышения производительности? Сама идея о том, что я могу быть в середине какой-то рутины и затем внезапно добраться до другой точки в коде, кажется немного неправильной... как злоупотребление try/catch в Java для выполнения программы.letcc
кажется, не существует в версии guile (1.8.7), которую я установил в OS X. Есть ли другое имя, которое я должен искать в guile?Если я неправильно понимаю
letcc
сравнивая его с try/catch в Java, или catch/throw в ruby (что не является обработкой исключений, просто для ясности для нерубиистов), как именно это работает на функциональном уровне? Можно ли выразить это более длинным, более сложным способом, который убедит меня, что он все-таки функционален?
1 ответ
"Функциональный" имеет несколько значений, но ни одно из популярных значений никак не противоречит продолжениям. Но они могут быть использованы для создания кода, который трудно читать. Это не инструменты, которыми можно "злоупотреблять для выполнения программ" - это инструменты длявыполнения программ.
Не могу помочь тебе там. Я знаю, что в Guile были недавние продолжения, но я не знаю, как обстоят дела. Это определенно должно иметь
call-with-current-continuation
обычно также под более дружеским именемcall/cc
, а такжеlet/cc
простой макрос, который может быть построен сcall/cc
,Я могу сказать вам, что в Racket есть
let/cc
Встроенный вместе с кучей других встроенных в том же семействе, и, кроме того, есть целая библиотека различных управляющих операторов (с обширным списком ссылок.).Простое использование
let/cc
действительно похожи на вещи типа "лови / бросай" - более конкретно, такие продолжения обычно известны как "продолжения побега" (или иногда "вверх"). Это тот тип использования, который вы используете в этом коде, и который часто используется для реализацииabort
илиreturn
,Но продолжения в Схеме - это вещи, которые можно использовать в любом месте. Для очень простого примера, демонстрирующего эту разницу, попробуйте следующее:
(define (foo f) (f 100)) (let/cc k (+ (foo k) "junk") (more junk))
Наконец, если вы хотите больше узнать о продолжениях, вы можете увидеть соответствующие части PLAI, есть также более краткий обзор на примерах, который написал Мэтью Майт, и вы можете увидеть некоторые заметки класса, которые я написал, которые основаны на PLAI, с некоторыми примерами, которые были вдохновлены последним постом.