5

環境

次のコードを検討してください

(defprotocol ICat "Foo"
  (meow [cat]))

(defrecord Cat [a b] "Cat"
  ICat
  (meow [cat] (some-expensive-operation a b)))

質問

どこかに let を投げる方法はありますか?

(some-expensive-operation ab) は、実行時に一度だけ評価されることをお勧めします

(->Cat a b)

そのため、(meow cat) の時点で、その場で再計算するのではなく、事前にキャッシュされた値を返すだけです。たとえば、次のようになります。

[1] (let [x (->Cat a b)]
[2]   (meow x)
[3]   (meow x)
[4]   (meow x))

(some-expensive-operation) を [1] で正確に 1 回評価してから、[2]、[3]、[4] に対しては古い値を返すだけです。

4

3 に答える 3

3

コストのかかる操作をコンストラクター関数で 1 回呼び出すロジックをラップし、結果を通常の値としてレコードに格納することをお勧めします。

(defprotocol ICat "Foo"
  (meow [cat]))

(defrecord Cat [a b] "Cat"
  ICat
  (meow [cat] (:meow cat)))

(defn make-cat [a b]
  (assoc (->Cat a b) :meow (some-expensive-operation a b)))

コードが複雑になると、いずれにしても独自のコンストラクター関数を定義したくなることがよくあります。

必要な場合にのみ計算されるように、高価な操作を遅延シーケンスまたは遅延でラップすることも検討する必要があることに注意してください。

于 2012-05-28T02:20:20.353 に答える
1

関数が参照透過的である場合は、関数を でラップできますmemoize。少なくとも、次のことができます。

(def memo-some-expensive-function (memoize some-expensive-function))

そしてmemo-some-expensive-function、あなたの記録に使用してください。

于 2012-05-27T23:16:48.113 に答える
0

これを回避する最も簡単な方法は、

  • defrecord のラッパーを作成する

  • このラッパーを使用すると、再計算する他のフィールドを指定できます

  • これらの追加フィールドを「実際の」defrecordに添付します

于 2012-05-27T23:38:26.380 に答える