2

厳密に評価されたリスト内包表記に従って、bangパターンの代わりにseqを使用するように書き直す方法が、少し行き詰まっています。

zipWith' f l1 l2 = [ f e1 e2 | (!e1, !e2) <- zip l1 l2 ]

何か案が ?

私はもう試した

zipWith' f l1 l2 = [ e1 `seq` e2 `seq` f e1 e2 | (e1, e2) <- zip l1 l2 ]

しかし、残念ながら、これはWHNFに評価を強制するものではありません。

4

3 に答える 3

6

強打パターンをGHCマニュアルseq に従う呼び出しに機械的に変換できます。

これ:

zipWith' f l1 l2 = [ f e1 e2 | (!e1, !e2) <- zip l1 l2 ]

怠惰になります:

zipWith' f l1 l2 =
    [ f e1 e2
    | e <- zip l1 l2
    , let t = case e of (x,y) -> x `seq` y `seq` (x,y)
    , let e1 = fst t
    , let e2 = snd t
    ]

これはより簡潔に(怠惰すぎる)と書かれています:

zipWith' f l1 l2 =
    [ f e1 e2
    | e <- zip l1 l2
    , let (e1,e2) = case e of (x,y) -> x `seq` y `seq` (x,y)
    ]

私はそれを(間違った、怠惰すぎる)と書きますが

zipWith' f l1 l2 = zipWith (\x y -> uncurry f (k x y)) l1 l2
    where
        k x y = x `seq` y `seq` (x, y)

厳密性のヒントをデータ構造に移動することもできます。

data P = P !Integer !Integer

zipWith' f l1 l2 = [ f e1 e2 | P e1 e2 <- zipWith P l1 l2 ]

またはとして:

zipWith' f l1 l2 = [ f e1 e2 | (e1, e2) <- zipWith k l1 l2 ]
    where
        k x y = x `seq` y `seq` (x,y)
于 2011-06-26T19:46:51.450 に答える
5

厳密に実行したい重要なことzipWithは、consセルが強制されたときにリストの要素を評価することです。あなたの関数はそれをしません。ちょうど試して

main = print $ length $ zipWith' undefined [1..10] [1..100]

これは、(+)を使用した場合の厳密性分析のまぐれであり、機能します。

必要な関数は次のようなものです。

zipW f (x:xs) (y:ys) = let z = f x y in seq z (z : zipW f xs ys)
zipW _ _ _ = []

前者は後者を強制する必要があるため、consセルの生成を値の生成から切り離すことはできません。

于 2011-06-26T22:45:36.497 に答える
3

元のポスターの例とドンの注目すべき行動のいくつかを説明するため。簡潔なconcatMapとして(>> =)を使用すると、元の例は次のように変換されます。

zip l1 l2 >>= \(!e1, !e2) -> [f e1 e2]

2番目の例は次のとおりです。

zip l1 l2 >>= \(e1, e2) -> [e1 `seq` e2 `seq` f e1 e2]

しかし、脱糖された最初のバージョンが実際にさらに脱糖するのは次のとおりです。

zip l1 l2 >>= \(e1, e2) -> e1 `seq` e2 `seq` [f e1 e2]

e1とe2は、concatMapのconcatがこれらのシングルトンリストをフラット化するときに強制されます。これにより、「進むにつれて強制する」動作が提供されます。

これは通常「厳密な」zipWithとは考えられませんが、fibsの例で機能するのはまぐれではありません。

于 2011-06-26T23:23:17.657 に答える