There are two strict versions of zipWith function:
1) Really strict, elements of lists l1 and l2 get evaluated so their thunks do not eat all stack space (Do开发者_如何转开发n Stewart code)
zipWith' f l1 l2 = [ f e1 e2 | (e1, e2) <- zipWith k l1 l2 ]
where
k x y = x `seq` y `seq` (x,y)
2) Not really strict, attempt to force evaluation by other way.
zipWith'' f l1 l2 = [ f e1 e2 | (e1, e2) <- zip (map (\x -> x `seq` x) l1) (map (\x -> x `seq` x) l2) ]
The question is: why the equivalent code from the 2nd example using map does not make the function also strict?
It's a common mistake to use
x `seq` x
Which is exactly equivalent to
x
An excellent explanation is available in Neil Mitchell's post on Bad Strictness.
Instead of tautological map
, one can use this function to force the list:
evl [] = []
evl (x:xs) = x `seq` (x:evl xs)
-- Cannot figure out how to do this with fold.
Then the strict zipWith
is
zipWith''' f xs ys = zipWith f (evl xs) (evl ys)
精彩评论