Вот что происходит:
Когда вы (define fact x!)
, вы не навсегда связываете fact
с x!
.Вы делаете fact
равным независимо от того, x!
на момент определения fact
.
Так что (define fact x!)
фактически эквивалентно:
(define fact
(lambda(x)
(if (= x 1) 1 (* x (x! (- x 1))))))
Далее вы переопределяете x!:
(define x! (lambda (x) x))
Но это не меняет fact
- оно только меняет x!
.Далее вы делаете это:
(fact 5)
Вот что «переводчик» «делает» дальше (он может на самом деле делать это немного по-другому - но только тривиально, и это должно как минимум помочь вам понять поведениевашей программы):
Замена fact
определением дает:
(lambda(x)
(if (= x 1) 1 (* x (x! (- x 1)))))
Замена x!
определением new дает:
((lambda(x)
(if (= x 1)
1
(* x
(- ((lambda (x)
x)
x)
1))))
5)
... Упрощение дает:
((lambda(x)
(if (= x 1)
1
(* x (- x 1))))
5)
...
(if (= 5 1)
1
(* 5 (- 5 1)))
...
(if #f
1
(* 5 (- 5 1)))
... Разрешение условного иупрощение вычитания дает:
(* 5 4)
... что дает 20.