如何在列表理解中设置严格性?

Dav*_*ric 2 haskell lazy-evaluation strictness

我有点困惑如何重写严格评估列表理解以使用seq而不是bang模式:

zipWith' f l1 l2 = [ f e1 e2 | (!e1, !e2) <- zip l1 l2 ]
Run Code Online (Sandbox Code Playgroud)

任何的想法 ?

我试过了

zipWith' f l1 l2 = [ e1 `seq` e2 `seq` f e1 e2 | (e1, e2) <- zip l1 l2 ]
Run Code Online (Sandbox Code Playgroud)

但不幸的是,这并未强制对WHNF进行评估.

Don*_*art 6

您可以机械地将爆炸模式转换为seq 遵循GHC手册的调用:

这个:

zipWith' f l1 l2 = [ f e1 e2 | (!e1, !e2) <- zip l1 l2 ]
Run Code Online (Sandbox Code Playgroud)

变得懒得:

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
    ]
Run Code Online (Sandbox Code Playgroud)

哪个更简洁地写成(太懒):

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)
    ]
Run Code Online (Sandbox Code Playgroud)

虽然我把它写成(错误,懒得)

zipWith' f l1 l2 = zipWith (\x y -> uncurry f (k x y)) l1 l2
    where
        k x y = x `seq` y `seq` (x, y)
Run Code Online (Sandbox Code Playgroud)

您还可以将严格提示移动到数据结构:

data P = P !Integer !Integer

zipWith' f l1 l2 = [ f e1 e2 | P e1 e2 <- zipWith P l1 l2 ]
Run Code Online (Sandbox Code Playgroud)

或者:

zipWith' f l1 l2 = [ f e1 e2 | (e1, e2) <- zipWith k l1 l2 ]
    where
        k x y = x `seq` y `seq` (x,y)
Run Code Online (Sandbox Code Playgroud)


aug*_*tss 5

您希望严格zipWith要做的基本事情是在强制使用cons单元时评估列表的元素.你的功能不会这样做.试一试

main = print $ length $ zipWith' undefined [1..10] [1..100]
Run Code Online (Sandbox Code Playgroud)

当您使用(+)使其工作时,这是严格性分析的侥幸.

你想要的功能是这样的:

zipW f (x:xs) (y:ys) = let z = f x y in seq z (z : zipW f xs ys)
zipW _ _ _ = []
Run Code Online (Sandbox Code Playgroud)

你不能将cons细胞的产生与价值的产生分开,因为前者应该强迫后者.