3

階乗を計算する関数の次の実装を考えてみましょう: [1]

(define fac-tail
  (lambda (n)
    (define fac-tail-helper
      (lambda (n ac)
        (if (= 0 n)
            ac
            (fac-tail-helper (- n 1) (* n ac)))))
    (fac-tail-helper n 1)))

let内部定義を使用して書き直そうとしました:

(define fac-tail-2
  (lambda (n)
    (let ((fac-tail-helper-2
            (lambda (n ac)
              (if (= 0 n)
                  ac
                  (fac-tail-helper-2 (- n 1) (* n ac))))))
    (fac-tail-helper-2 n 1))))

その時点でエラーはありませんdefineが、実行結果は次のようになります。

#;> (fac-tail-2 4)
Error: undefined variable 'fac-tail-helper-2'.
{warning: printing of stack trace not supported}

letバージョンを機能させるにはどうすればよいですか?

スキームのバージョンは SISC v 1.16.6 です

[1] SICP http://mitpress.mit.edu/sicp/full-text/book/book-ZH-11.html#%_sec_1.2.1factorialのセクション 1.2.1 の反復バージョンに基づく

4

3 に答える 3

8

let バージョンを機能させるにはどうすればよいですか?

letrecの代わりに使用しletます。

于 2010-07-02T22:56:33.517 に答える
6

R. Kent Dvbvig 言います:


実際、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れた本体のパラメーターとして表示される名前ですが、 parameter に割り当てられている内の名前ではないことが明らかになります。lambdalambdafac-tail-helper-2

[1] The Scheme Programming Language、第 4 版の セクション 2.5、「ラムダ式」http://scheme.com/tspl4/start.html#SECTGSLAMBDA

于 2010-07-02T22:30:26.087 に答える
0

完全を期すために追加された他の2つの選択肢。

Schemeプログラミング言語、第4版セクション3.2にはlet、再帰関数を使用するための他の2つの選択肢があります。http://scheme.com/tspl4/further.html#./further:h2

1つ目は賢く、お勧めできません。それは、それが呼び出すラムダであるラムダにパラメーターを追加し、次にそれ自体を渡してすべてを開始することを含みます。

(define fac-tail-4
  (lambda (n)
    (let ((fac-tail-helper
            (lambda (fac-tail-helper n ac)
              (if (= 0 n)
                  ac
                  (fac-tail-helper fac-tail-helper (- n 1) (* n ac))))))
      (fac-tail-helper fac-tail-helper n 1))))

そして、より単純な名前は、単一の再帰letの内部で使用できます。letrec

(define fac-tail-3
  (lambda (x)
    (let fac-tail-helper ((n x) (ac 1))
      (if (= 0 n)
          ac
          (fac-tail-helper (- n 1) (* n ac))))))

そのバージョンは、fac-tail-helperに関連付けられている暗黙のラムダ定義を非表示にします。

于 2010-07-06T16:46:05.707 に答える