強打パターンを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)