Помощь в понимании продолжения схемы
-
19-09-2019 - |
Вопрос
Я работал вместе с Маленькая схема Чтобы изучить схему и использовать Plt-Scheme для моей среды.
Маленькая схема очень помог мне в рекурсии (сейчас это просто для меня), но я застрял в части книги, которая вводит «коллекционеров» и называет функцию в целом продолжением.
Вот пример кода, который они использовали. Я понимаю рекурсивные элементы, но я застрял, в частности, на функциях лямбды - мой разум не может следовать по пути и того, как установлены аргументы для этой функции лямбды (поскольку их единственный призыв - снова вызвать их в рекурсии, есть Нет конкретного использования в корпусе функции).
Если бы кто-то мог более или менее дать мне разрыв пути вычислений посредством рекурсии функции в коллекционеров лямбда, это может помочь мне.
;; Build a nested list of even numbers by removing the odd ones from its
;; argument and simultaneously multiply the even numbers and sum the odd
;; numbers that occur in its argument.
(define (even-only-collector l col)
(cond
((null? l)
(col (quote ()) 1 0))
((atom? (car l))
(cond
((even? (car l))
(even-only-collector (cdr l)
(lambda (newl p s)
(col (cons (car l) newl)
(* (car l) p) s))))
(else
(even-only-collector (cdr l)
(lambda (newl p s)
(col newl
p (+ (car l) s)))))))
(else
(even-only-collector (car l)
(lambda (al ap as)
(even-only-collector (cdr l)
(lambda (dl dp ds)
(col (cons al dl)
(* ap dp)
(+ as ds)))))))))
;; The collector function
(define (collector newl product sum)
(cons sum
(cons product newl)))
Заранее спасибо!!
Решение
Попробуйте что -нибудь проще, чтобы увидеть, как это работает. Например, вот версия list-sum
функция, которая получает аргумент продолжения (который часто называют k
):
(define (list-sum l k)
(if (null? l)
???
(list-sum (cdr l) ???)))
Основной шаблон существует, и недостающие части - это то, где происходят интересные вещи. Аргумент продолжения - это функция, которая рассчитывает получить результат - поэтому, если список нулевой, ясно, что мы должны отправить его 0
, поскольку это сумма:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) ???)))
Теперь, когда список не является нулевым, мы рекурсивно называем функцию хвостом списка (другими словами, это итерация), но вопрос в том, каким должно быть продолжение. Делая это:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) k)))
явно неправильно - это означает, что k
в конечном итоге получит сумму (cdr l)
вместо всех l
. Анкет Вместо этого используйте там новую функцию, которая подведет итог первого элемента l
Слишком вместе со значением, которое он получает:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) (lambda (sum) (+ (car l) sum)))))
Это становится все ближе, но все же неправильно. Но это хороший момент, чтобы подумать о том, как все работает - мы звонят list-sum
С продолжением, которое само по себе получит общую сумму, и добавите первый пункт, который мы видим сейчас. Пропавшая часть очевидна в том, что мы игнорируем k
. Анкет Нам нужно составить k
С помощью этой функции - поэтому мы выполняем ту же работу, а затем отправляем результат на k
:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) (compose k (lambda (s) (+ s (car l)))))))
который наконец работает. (Кстати, помните, что каждый из них lambda
Функции имеют свою «копию» l
.) Вы можете попробовать это с:
(list-sum '(1 2 3 4) (lambda (x) x))
И, наконец, обратите внимание, что это то же самое, что:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) (lambda (s) (k (+ s (car l)))))))
Если вы сделаете композицию явной.
(Вы также можете использовать этот код на языке студентов промежуточного+Lambda и щелкнуть кнопку «Шата», чтобы увидеть, как происходит оценка - это займет некоторое время, но вы увидите, как функции продолжения вложены, каждый с собственным представлением о списке.)
Другие советы
Вот один из способов помочь вам «получить более конкретную идею». Представьте себе, если коллекционер был определен таким образом:
(define (collector l p s)
(display l)
(newline)
(display p)
(newline)
(display s)
(newline))
Вы можете увидеть в базовом случае, если вы пройдете в пустом списке, он позвонит вашей функции с аргументами '()
, 1, и 0. Теперь работайте с одноэлементным списком и посмотрите, что он назовет вашу функцию. Продолжайте работать с более длинными и более длинными списками, пока вы не поймете, что происходит.
Удачи!