Схема результата функции - PullRequest
2 голосов
/ 27 июня 2010

На схеме я встретил следующий код:

(define x! 
  (lambda(x)
    (if (= x 1) 1 (* x (x! (- x 1))))))

(define fact x!)

(define x! (lambda (x) x))
(fact 5)

Мне все ясно, пока не переопределим х! и увидеть результат функции (20). Как это можно объяснить? .. Почему это 20, а не 5! = 120. Заранее спасибо

Ответы [ 5 ]

4 голосов
/ 27 июня 2010

Вот что происходит:

Когда вы (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.

3 голосов
/ 27 июня 2010

сначала вы определяете х!чтобы быть способом вычисления факториала (то есть (x! 5) = 120).
Тогда вы определяете факт как то, что x!is, это та же самая функция (то есть fact = lambda(x) (if (= x 1)... Затем вы меняете то, что x! является тождеством. Однако, fact - это все та же функция, вы не изменили ее, но эта функция ссылается на x! внутренне,поэтому он в конечном итоге вызывает факт (который вы определили первым), который вызывает функцию идентификации.

, поэтому (fact 5) - это то же самое, что:

(if (= 5 1) 1 (* 5 (x! (- 5 1))))))

, что совпадает с:

(if false 1 (* 5 (x! 4)))

, что совпадает с:

(if false 1 (* 5 4))

, что совпадает с:

(* 5 4)

, что 20

3 голосов
/ 27 июня 2010

Способ, которым Схема ведет себя, когда у вас есть переопределение идентификатора, состоит в том, чтобы использовать set! для него.В вашем случае, если вы замените переопределение на

(set! x! (lambda (x) x))

, тогда результат станет более понятным.

(Обратите внимание, что не все схемы делают это...)

2 голосов
/ 27 июня 2010

Хорошо, здесь происходит следующее:

Когда вы делаете (x! (- x 1)) внутри исходного определения x!, вы вызываете функцию с именем x!. Поэтому, если вы измените то, что означает имя x!, это повлияет на этот вызов на x!.

Когда вы делаете (define fact x!), факт ссылается не на имя x!, а на текущее содержимое x!, т.е. на функцию, которую вы только что определили.

Теперь вы измените значение имени x! и затем позвоните (fact 5). Сначала это вызовет исходное определение x! (потому что это тот факт, к которому относится факт), однако, когда он добирается до вызова (x! (- 5 1)), он вызывает новое определение x!, которое возвращает 4, поэтому вы получаете 5 * 4 = 20.

0 голосов
/ 18 декабря 2014

Примечание с одной стороны: вам нужно использовать модель среды, чтобы понять ее. Потому что ответы на подобные вопросы отличаются лексической областью и динамической областью действия.

...