Давайте рассмотрим, что вы many
делаете. Сначала вы определили это:
(define (many n fn)
(cond
[(= n 0) true]
[else (many (sub1 n)
(local ((define k (time fn)))
k))]))
Тогда назовите это:
> (many 3 (add1 41))
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
#t
>
Вот что происходит на каждой итерации, когда many
вызывает себя рекурсивно:
(define (many 3 42)
(cond
[(= 3 0) true]
[else (many (sub1 3)
(local ((define k (time 42)))
42))]))
(define (many 2 42)
(cond
[(= 2 0) true]
[else (many (sub1 2)
(local ((define k (time 42)))
42))]))
(define (many 1 42)
(cond
[(= 1 0) true]
[else (many (sub1 1)
(local ((define k (time 42)))
42))]))
(define (many 0 42)
(cond
[(= 0 0) true]
[else (many (sub1 0)
(local ((define k (time 42)))
42))]))
Ваше определение many
рекурсивно вызывает себя со значением результата первого (time fn)
приложения, но это неверно, потому что вы хотите собрать информацию о времени для вашего приложения процедуры, а не значение (значение (add1 41)
в нашем случае). Просто замените true
на fn
в вашем определении many
:
(define (many n fn)
(cond
[(= n 0) fn]
[else (many (sub1 n)
(local ((define k (time fn)))
k))]))
и вы получите следующее:
> (many 3 (add1 41))
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
cpu time: 0 real time: 0 gc time: 0
42
>
Вы видите, что fn
на каждом рекурсивном вызове равно 42
. Это происходит потому, что многие (если не все) языки FP используют Аппликативный порядок оценки, а (add1 41)
оценивается до первого вызова many
.
Таким образом, мы должны использовать lambda
, чтобы функция ( thunk в нашем случае) передавалась многим в качестве второго аргумента (fn
). Как вы уже знаете, применение функции в схеме выражается как ()
вокруг выражения:
(define (many n fn)
(time (fn))
(if (= n 0)
true
(many (sub1 n) fn)))
Пример вывода:
> (many 3 (lambda () (fact 10000)))
cpu time: 2734 real time: 2828 gc time: 1922
cpu time: 906 real time: 953 gc time: 171
cpu time: 891 real time: 953 gc time: 204
cpu time: 938 real time: 984 gc time: 251
#t
>
Как вы видите выше (fn)
выполняет применение результата функции (lambda () (fact 10000)
(thunk), time
получает именно то, что вы хотели передать (выражение), и отображает правильную информацию о времени.
Надеюсь, это поможет. Поправь меня, если я ошибаюсь.