3

x次の関数では、コンパイラが十分に賢く、一定のままになるのか、それともリスト内のすべての項目のリストの先頭を計算するのか疑問に思っています。(私はGHCを使用しています)

allSame :: Eq a => [a] -> Bool 
allSame xs = all (==x) xs  where x = head xs
4

2 に答える 2

11

GHC における 'where' のセマンティクスは、単一のクロージャが 'x' に割り当てられ、すべての用途で共有されるというものです。関数 (== 'x') の新しいクロージャが生成され、オプティマイザがそれをフロートアウトするため、トラバーサルごとに 1 回だけ生成されます。

生成されたコードを正確に確認するには、Core をチェックします (例: ghc-core 経由)。GHC はコードを次のように最適化します。

M.allSame a eq xs =
    all
      (let 
         ds =
           case xs of 
             []   -> error "bad head"
             x : _-> x
            in
          \y -> x == y
         ) xs

パフォーマンスが懸念される場合は、ベクターの使用を検討してください。個別のトラバーサルが融合し、再帰が削除されるためです。

于 2010-08-27T05:32:06.190 に答える
0

Haskell は必要なものを評価するだけだと思いxますwherex次に、一度計算してall.

テストしたい場合myallは、のように再帰を行う関数を書くことができますがall (==x)、基本的には比較要素を出力するだけです。したがって、毎回新しい引数を取得するか、毎回同じままであるかがわかります。

編集:

これをテストするための小さな関数を次に示しmyallます。最初の引数を収集してリストに入れるだけです。

myall x [] = [x]
myall x xs =  x:(myall x (tail xs))

test xs = myall (x) xs where x = head xs

を呼び出すとtest [1,2,3]、結果が であることがわかります[1,1,1,1]。つまり、最初xに が評価され1、その後myallが評価されます。

于 2010-08-27T05:29:08.293 に答える