Попробуйте что-нибудь попроще, чтобы увидеть, как это работает. Например, вот версия функции 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)))))))
если вы сделаете композицию явной.
(Вы также можете использовать этот код на языке промежуточного + лямбда-студента и нажать кнопку «шаговый», чтобы увидеть, как проходит оценка - это займет некоторое время, но вы увидите, как функции продолжения вложенный, каждый со своим собственным представлением списка.)