8

このコードを最適化する方法に興味があります:

fun n = (sum l, f $ f0 l, g $ g0 l)
  where l = map h [1..n]

ff0gg0、およびhはすべてコストがかかると仮定しますが、 の作成と保存にlは非常にコストがかかります。

書かれているようにl、返されたタプルが完全に評価されるかガベージ コレクションされるまで格納されます。代わりに、length lf0 l、およびg0 lのいずれかが実行されるたびにすべて実行する必要がfありますが、 およびgは遅延させる必要があります。

この動作は、次のように書くことで修正できるようです:

fun n = a `seq` b `seq` c `seq` (a, f b, g c)
  where
    l = map h [1..n]
    a = sum l
    b = inline f0 $ l
    c = inline g0 $ l

または非常に似ています:

fun n = (a,b,c) `deepSeq` (a, f b, g c)
  where ...

同じ効果を実現するために内部型の束を指定することもできますが、これは面倒に見えます。他のオプションはありますか?

inlineまた、コンパイラsumが 、f0、およびを融合して、項g0ごとに構築および消費する単一のループにすることを明らかに望んでいます。l手動でインライン化することでこれを明示的にすることもできますが、それは最悪です。リストが作成されないように明示的に防止したり、lインライン化を強制したりする方法はありますか? コンパイル中にインライン化または融合が失敗した場合に警告またはエラーを生成するプラグマはおそらく?

余談ですが、プレリュードで 、 、 などがすべて by にseq定義inlinelazyれている理由が気になります。let x = x in xこれは単に、コンパイラがオーバーライドする定義を提供するためですか?

4

1 に答える 1

3

確実にしたい場合は、自分でやるしかありません。任意のコンパイラ バージョンについて、いくつかのソース形式を試して、生成されたコア/アセンブリ/llvm バイトコードなどをチェックして、それが目的どおりに動作するかどうかを確認できます。しかし、それはコンパイラの新しいバージョンごとに壊れる可能性があります。

あなたが書くなら

fun n = a `seq` b `seq` c `seq` (a, f b, g c)
  where
    l = map h [1..n]
    a = sum l
    b = inline f0 $ l
    c = inline g0 $ l

またはそのバージョンの場合、コンパイラは の計算をマージして、の 1 回のトラバーサル中に (並行性の意味ではなく) 並列に実行deepseqできるかもしれませんが、当分の間、GHC はそうではないと確信しています。 t、そしてJHCまたはUHCがそうであったなら、私は驚くだろう. そのためには、コンピューティングの構造が十分に単純である必要があります。abclbc

コンパイラとコンパイラのバージョン間で移植可能な目的の結果を得る唯一の方法は、自分で行うことです。少なくとも今後数年間は。

f0とによってはg0、有名な平均のように、適切なアキュムレータ タイプと結合関数を使用して厳密な左折畳みを行うのと同じくらい簡単かもしれません。

data P = P {-# UNPACK #-} !Int {-# UNPACK #-} !Double

average :: [Double] -> Double
average = ratio . foldl' count (P 0 0)
  where
    ratio (P n s) = s / fromIntegral n
    count (P n s) x = P (n+1) (s+x)

f0しかし、 and/orの構造がg0適合しない場合、たとえば、一方が左の折り畳みで、もう一方が右の折り畳みである場合、1 回のトラバーサルで計算を行うことは不可能な場合があります。このような場合は、再作成するかl保存するかの選択になりlます。格納lは明示的な共有 ( where l = map h [1..n]) で簡単に実現できますが、コンパイラが一般的な部分式の削除を行う場合、再作成は困難になる可能性があります (残念ながら、GHC は、CSE をほとんど実行しないにもかかわらず、その形式のリストを共有する傾向があります)。GHC の場合、フラグfno-cseとフラグ-fno-full-lazinessは不要な共有を避けるのに役立ちます。

于 2012-04-22T12:41:34.653 に答える