Вложенная функция в программировании

#scheme #lisp

#схема #lisp

Вопрос:

Я читаю метод Ньютона в SICP, где он вводит блочную структуру, в которую вложена функция, скажем

 (define (sqrt x)
    (define (good enough ? guess x)
             (<(abs(-(square guess) x)) 0.001))
    (define (improve guess x)
             (average guess (/ x guess)))
    (define (sqrt-iter guess x)
        (if (good-enough? guess x)
        guess
        (sqrt-iter(improve guess x)x))) 
(sqrt-iter 1.0 x))

  

Я в замешательстве, потому что, в моем понимании вложенности, «достаточно хорошо?» и «улучшить предположение» должны быть вложены
в тело «sqrt-iter», а «sqrt iter» должен быть помещен в тело «sqrt x»

 (define (sqrt x)
   (sqrt-iter 1.0 x
      (define (sqrt-iter guess x)
        (if (good-enough? guess x)
        guess
        (sqrt-iter(improve guess x)x)
             (define (good enough ? guess x)
                 (<(abs(-(square guess) x)) 0.001))
             (define (improve guess x)
                 (average guess (/ x guess)))
       )) 
    ))
  

почему это не так.Я использую LISP

Ответ №1:

Обратите внимание, что sqrt-iter это уже определено внутри тела sqrt . Но то, как вы это написали, не имеет смысла, вы пытаетесь вызвать sqrt-iter , но определяете его внутри вызова в качестве третьего параметра. Это неправильно:

 (sqrt-iter 1.0 x (define (sqrt-iter ...)))
  

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

 (define (sqrt-iter guess x) ...) ; first define
(sqrt-iter 1.0 x) ; after defining, you can call it
  

Ваше другое предложение имеет больше смысла, можно было бы определить good-enough? и improve внутри sqrt-iter , но, возможно, это понятнее в том, как они написали это в книге. Это допустимо, но имеет тот недостаток, что good-enough? и improve будет переопределяться при каждом sqrt-iter вызове:

 (define (sqrt x)
  (define (sqrt-iter guess x)
    (define (good-enough? guess x)
      (< (abs (- (square guess) x)) 0.001))
    (define (improve guess x)
      (average guess (/ x guess)))
    (if (good-enough? guess x)
        guess
        (sqrt-iter (improve guess x)x))) 
  (sqrt-iter 1.0 x))
  

Вам следует более внимательно прочитать раздел книги, в котором объясняется, как процедуры определяются и используются в Scheme, вы, кажется, путаете понятия, смешивая параметры, определения процедур и вызовы процедур.

Комментарии:

1. так что насчет «достаточно хорошо?» и «улучшить предположение», его можно поместить под определение «sqrt-iter», но не внутри тела, почему он не ставит «достаточно хорошо?» и «улучшить предположение» под «sqrt-iter»

2. @89085731 Я обновил свой ответ, их можно перемещать, но все же я предпочитаю исходную версию, как она приведена в книге — ее легче читать.

3. Меня беспокоит то, что если мы не поставим «достаточно хорошо» и «улучшить предположение» под «sqrt-iter», то эти две функции лежат на одном уровне «sqrt-iter», но не отношение вложенных

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

5. Не беспокойтесь о вложенности 😉 используйте ее только в том случае, если таким образом вы можете избежать некоторых параметров при определении новых процедур. И будьте осторожны при вложении процедур, определения должны быть только в начале процедуры, а не в произвольных местах.