Я пытаюсь написать цикл в схеме, используя named let. Я хотел бы иметь возможность выйти из итерации раньше, основываясь на различных критериях, а не всегда зацикливаться прямо в конце. По сути, я хотел бы иметь while
, break
и continue
. Я вынужден использовать guile 1.8 по веским причинам, а guile 1.8 не реализует конструкцию R6RS while
. Мой вопрос: должна ли рекурсия с использованием named let быть хвостовой рекурсией, и почему вы не можете перезапустить цикл до конца? [Нужен ли для этого пример кода?] Когда я пытаюсь рекурсивно использовать ранний выход в нескольких точках с операциями ввода-вывода, я неизменно считываю последний EOF и получаю непредсказуемое повреждение данных.
Именованный пусть в схеме
Ответы (1)
(let name ((iter iter-expr) (arg1 expr1) (arg2 expr2))
(cond
(continue-predicate (name (next iter) arg1 arg2)))
(break-predicate break-expression-value)
(else (name (next iter) next-arg1-expression next-ar2-expression))))
Продолжение просто вызывает снова, используя большинство тех же аргументов без изменений, за исключением итерированных частей, которые изменятся на следующее.
Перерыв — это базовый случай.
Так что же такое while
? Это имя let
с предикатом разрыва и регистром по умолчанию.
Scheme на самом деле не имеет конструкции while
. Если вы прочтете отчет, то увидите, что это просто синтаксический сахар (макрос), который превращается во что-то вроде имени let
.
Вам нужно, чтобы он был хвостовым рекурсивным, если вы хотите иметь возможность выйти из него без выполнения всех предыдущих вычислений. Вы также можете использовать call/cc
для предоставления продолжения выхода, которое, по сути, заставляет Scheme делать это за вас под капотом. Обычно call/cc
довольно далеко для новичков, и для освоения требуется некоторое время, поэтому сделать ваши процедуры рекурсивными хвостами легче для понимания, чем делать что-то вроде этого:
(define (cars lists-of-pair)
(call/cc (lambda (exit)
(fold (lambda (e a)
(if (pair? e)
(cons (car e) a)
(exit '()))) ; throw away continuations to make current result make it ()
'()
lists-of-pair)))
(cars '((1 2) (a b))) ; ==> (1 a)
(cars '((1 2) ())) ; ==> ()
while
выполняет рекурсию, если предикат истинен, поэтому вы можете думать об этом как о рекурсии, если только не сработает отрицательный базовый случай. Таким образом, break
с (not while-predicate)
в качестве предиката. continue
обычно имеет рекурсию, как и случай по умолчанию, но с меньшим количеством вычислений.
- person Sylwester; 22.05.2017
while
,break
иcontinue
: это звучит так, как будто вы пытаетесь импортировать императивные идеи (стиль C) в неимперативный язык и, таким образом, пытаетесь написать чрезвычайно унидиоматическую схему. - person Norman Gray   schedule 22.05.2017break
иcontinue
, то искать будете долго, так как непосредственных аналогов тем в схемах нет. - person Norman Gray   schedule 22.05.2017