(define twice-the-stream
(lambda (n)
(letrec ([produce (lambda (current next)
(cons (* 2 current)
(lambda()
(produce (current next) (force (next))))))])
;; this is wrong: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(produce (car n) (force (cdr n))))))
Вы уже нанесли (cdr n)
в этот момент; теперь next
не является функцией, это поток - минусовая пара его текущий номер и его поток-хвост.
current
также не является функцией. Это номер, уже используемый для создания удвоенного номера выше этого звонка.
Чтобы уменьшить когнитивную нагрузку, переименовывать переменные, чтобы напомнить вам, что они есть,
(define twice-the-stream
(lambda (numbers-stream)
(letrec ([produce (lambda (current-num next-str)
(cons (* 2 current-num)
(lambda()
(produce (current-element next-str)
(force (next-elements next-str))))))])
(produce (car numbers-stream) (force (cdr numbers-stream))))))
и теперь вы можете видеть, что вы запутались по чрезмерно наводящим (и под специализированные) именовании, объединив в своем уме «текущий» номер с функцией «текущий номер» и «следующий» поток с функцией «следующий поток». Разбивая заклинание, теперь ясно, что нужно сделать, чтобы привести два вызова produce
в синхронизацию.
Кстати, если бы вы использовали более короткие имена переменных - в первую очередь, ns
для «потока чисел», n
для «ряда», s
для «потока», вы бы иметь немного меньше шансов запутаться,
(define twice-the-stream
(lambda (ns) ;; a numbers stream
(letrec ([produce (lambda (n s) ; a number, and a stream
(cons (* 2 n) ; a number, doubled
(lambda() ; a stream, repackaged:
(produce (.... s) ; _its_ 1st element
(force (.... s))))))]) ; and the rest
(produce (car ns) (force (cdr ns))))))
так делать то, что вы должны делать (предположительно) - то есть, используя описательные имена (но не достаточно описательные) - это то, что у вас в эта проблема во-первых!
якобы не очень хорошая вещь - но до тех пор, как они четко описаны в комментариях, я не понимаю, почему это должно быть так.