2015-07-29 2 views
1

поэтому я пытаюсь понять этот кусок кода, и после того, как смотрел на нее слишком долго я решил спросить здесь, если кто-нибудь может помочь мне понять, как и почему это работаетВозникли проблемы с функцией в схеме

(define knock-knock 
(letrec ([dig (lambda (i) 
       (cons (* i (list-ref knock-knock (- i 1))) 
         (dig (+ i 1))))]) 
    (cons 1 (dig 1)))) 

функция затем вызывается по имени со значением:

(list-ref knock-knock 5) 

Так что моя основная проблема заключается в том, что я не могу видеть, где letrec закончится. другое дело в том, что мне не присваивается список, так что это 4-й элемент в списке, который я должен ссылаться в строке 3?

+0

'knock-knock' не является функцией. это значение, созданное '(cons 1 (dig 1))' внутри 'letrec'. –

ответ

2

Во-первых, примечание: это не нормальная схема, так как она требует ленивой оценки.

В ленивой оценке значения вычисляются только тогда, когда они необходимы. Таким образом, для определения knock-knock, мы можем просто сделать

(cons 1 <thunk: (dig 1)>) 

т.е. мы генерируем пару, но нам не нужен второй элемент, поэтому мы отложить оценку до позже.

Когда мы действительно хотим оценить второй элемент, у нас уже будет установлен knock-knock, поэтому мы можем ссылаться на него.

Следующий элемент вычисляется путем принятия предыдущего элемента (i-1 -st) и умножает его на i. Таким образом, это будет генерировать ряд {п!}: 1,1,2,6,24, ...

Прямолинейный перевод этого кода в (обычно ленивый) Haskell язык выглядит следующим образом:

knock :: [Int] 
knock = 1 : dig 1 
    where dig i = (i * knock !! (i-1)) : dig (i+1)