5

私はこの関数を持っています(フィボナッチ数列を生成します):

unfoldr (\(p1, p2) -> Just (p1+p2, (p1+p2, p1)) ) (0, 1)

ここで、繰り返しの式に気づきましたp1+p2。これは、1回だけ計算されるように因数分解したいと思います。加算自体は高価な計算ではありませんが、より一般的なバージョンの場合:

unfoldr (\(p1, p2) -> Just (f p1 p2, (f p1 p2, p1)) ) (0, 1)
    where f = arbitrary, possibly time-consuming function

上記の状況でf p1 p2は、は2回計算されます(私が知らない魔法のコンパイラの最適化がない限り)。これによりf、大量の計算が必要な場合にパフォーマンスのボトルネックが発生する可能性があります。私は理由を考慮f p1 p2に入れることができず、範囲内にありません。この式を因数分解して、 1回だけ計算されるようにするための最良の方法は何ですか?wherep1p2f

4

2 に答える 2

9
unfoldr (\(p1, p2) -> let x = f p1 p2 in Just (x, (x, p1)) ) (0, 1)
    where f = arbitrary, possibly time-consuming function
于 2010-07-10T13:24:35.573 に答える
2

このようなもので使用できるものがありますControl.Arrow(&&&)

unfoldr (\(p1,p2) -> (Just . (id &&& flip (,) p1)) (p1+p2)) (0,1)

あるいは:

unfoldr (Just . (fst &&& id) . (uncurry (+) &&& fst)) (0,1)

同様に、あなたの例p1+p2では実際に次のp1ように書き直すことができます

tail (unfoldr (\(p1, p2) -> Just (p1, (p1+p2, p1)) ) (0, 1))
于 2010-07-10T13:44:14.033 に答える