Одним из таких способов является использование стиля прохождения продолжения.Здесь мы добавляем параметр с именем return
, который эффективно кодирует поведение, напоминающее возврат, с помощью лямбды.double
теперь принимает два аргумента: список удваивается, xs
и продолжение результата, return
-
(define (double xs return)
(if (empty? xs)
(return empty)
(double (cdr xs)
(lambda (result)
(return (cons (* 2 (car xs))
result))))))
В качестве примера, результатdouble
, примененный к списку '(1 2 3)
, отправляется на print
(double '(1 2 3) print)
;; '(2 4 6)
;; => #<void>
double
, что соответствует конечному продолжению;в этом случае print
оценивается как #<void>
.Мы можем использовать функцию identity
для эффективного вывода значения -
(double '(1 2 3) identity)
;; => '(2 4 6)
Racket позволяет легко указывать аргументы по умолчанию, поэтому мы можем изменить double
, чтобы использовать identity
в качестве продолжения по умолчанию
(define (double xs <b>(return identity))</b>
;; ...
)
Этот стиль позволяет создавать удобные программы, которые работают одновременно в двух стилях вызова: стиль продолжения -
(double '(10 11 12) print)
;; '(20 22 24)
;; => #<void>
(double '(10 11 12) length)
;; => 3
(double '(10 11 12) car)
;; => 20
(double '(10 11 12) cdr)
;; => '(22 24)
... или в прямом стилес использованием identity
продолжения по умолчанию
(print (double '(10 11 12)))
;; '(20 22 24)
(length (double '(10 11 12)))
;; => 3
(car (double '(10 11 12)))
;; => 20
(cdr (double '(10 11 12)))
;; => '(22 24)