R. Кент Двбвиг говорит:
На самом деле выражение let
является синтаксическим
расширение определено в терминах лямбда и процедура применения, которая
обе основные синтаксические формы. В общем, любое выражение вида
(let ((var expr) ...) body1 body2 ...)
эквивалентно следующему.
((lambda (var ...) body1 body2 ...)
expr ...)" [1]
Это означает, что fac-tail-2
эквивалентно:
(define fac-tail-2
(lambda (n)
((lambda (fac-tail-helper-2)
(fac-tail-helper-2 n 1)) ;; <== scope where fac-tail-helper-2 is visible.
(lambda (n ac) ;; this lambda is assigned to fac-tail-helper-2
(if (= 0 n)
ac
(fac-tail-helper-2 (- n 1) (* n ac))))))) ;; <=== problem
И становится ясно, что проблема в том, что имя fac-tail-helper-2
отображается как
параметр в теле lambda
выделен выше, но не является именем
внутри lambda
, назначенного параметру fac-tail-helper-2
.
[1] Раздел 2.5, «Лямбда-выражения» из Язык программирования схем, 4-е издание http://scheme.com/tspl4/start.html#SECTGSLAMBDA