1

指定された演算子で値の間隔を累積し、初期値を追加する関数を作成しようとしています。例:

(累積間隔+ 0 2 4):2 + 3 + 4 + 0 = 9

(累積間隔* 1 2 5):2 * 3 * 4 * 5 * 1 = 120

注:動作するには(+)と(*)だけで十分です。

私のコードは次のとおりです。

(define accumulate-interval
  (lambda (op init lower upper) (if (= upper lower)
   (lambda (x) (op x init))
    (lambda (x)
      (op
      ((accumulate-interval op init lower (- upper 1)) x))))     ))

値の代わりにプロシージャを返します。よろしくお願いします。

4

2 に答える 2

2

コードにいくつかの概念上の問題があります。私は@itsbruceに同意します。質問で見つかった各エラーを修正するよりも、正しい解決策の方法であなたを指摘する方が簡単です。

まず、プロシージャは既存の高階関数の観点から記述できることに注意してください。foldr値を累積し、値build-listの範囲を作成します。

(define (accumulate-interval op init lower upper)
  (foldr op init
         (build-list (add1 (- upper lower))
                     (lambda (x) (+ lower x)))))

または、Racketfor/listで、値の範囲を作成するために使用できます。

(define (accumulate-interval op init lower upper)
  (foldr op init
         (for/list ([n (in-range lower (add1 upper))]) n)))

ソリューションを最初から作成する必要がある場合(おそらくそうです)、問題を部分に分割することをお勧めします。まず、数値の範囲を生成します。

(define (range lower upper)
  (if (> lower upper)
      '()
      (cons lower
            (range (add1 lower) upper))))

ここで、値を累積します。

(define (accumulate op init lst)
  (if (null? lst)
      init
      (op (car lst)
          (accumulate op init (cdr lst)))))

最後に、前の2つのヘルパー手順を組み合わせて問題の解決策を作成します。最初の2つのソリューションでは、まったく同じ問題分解(最初:範囲の生成、2番目:累積、3番目:結合)を行ったことに注意してください。唯一の違いは、既存の手順を使用する代わりに、ヘルパー手順を手動で記述したことです。

(define (accumulate-interval op init lower upper)
  (accumulate op init
              (range lower upper)))

もちろん、ソリューションのようにすべての手順を1つにマージすることもできます。これは、数値の中間リストを作成しないため、より効率的です。

(define (accumulate-interval op init lower upper)
  (if (> lower upper)
      init
      (op lower
          (accumulate-interval op init (add1 lower) upper))))

...しかし、そうすることで、他のコンテキストで役立つ一連の構成可能な手順ではなく、1つの特定の問題に対してカスタマイズされたソリューションが生成されます。関数型プログラミングスタイルでは、ジェネリックで再利用可能な関数を定義することが推奨されます。

とにかく、これは期待どおりに機能します。

(accumulate-interval + 0 2 4)
> 9

(accumulate-interval * 1 2 5)
> 120
于 2012-10-16T15:35:34.540 に答える
1

それがあなたが返しているものであるため、それは関数を返します。 lambdaは、無名関数を作成し、その関数への参照を返す関数です。あなたのコードがそうするとき

(define accumulate-interval (lambda (op init lower upper) ......))

ラムダを使用して無名関数を作成し、その参照を返し、その参照をaccumulate-intervalの値として割り当てます。 したがって、 accumulate-intervalはその関数に関連付けられ、その関数は、accumulate-intervalがリスト内の関数の位置で評価されるたびに実行されます。

これで、accumulate-interval関数は、単一のif式で構成されます。

(if (= upper lower) (lambda (x) ...) (lambda (x) ...))

したがって、upperlowerが等しい場合は、1つの無名関数への参照を返します。それ以外の場合は、別の無名関数を返します。これはあなたがそれをするように言ったことです。

ここでは、あなたが何をしようとしているのかわかりませんが、誤って関数にラップして戻ってきたコードを実行したいだけだと思います。だから私はあなたのコードがもっと似ているように見えることを意図していると思います

(if (= upper lower)
  (op upper init) (op lower (accumulate-interval op init (+ lower 1) upper)))

これはうまくいくはずですが、その再帰呼び出しはテール位置にないため、引数を再考する必要があると思います。

考えてみて

(if (= upper lower)
   (op upper init)
   (accumulate-interval (op upper init) lower (- upper 1)))

動作し、末尾再帰になります。

注:私は通常、人々の宿題をしませんが、Schemeの構文について複数の誤解があり、動作するコードを表示する方が、考えられる誤解を個別に組み合わせて調べるよりも簡単だったと思います。

于 2012-10-16T15:19:53.580 に答える