Two calls to `seq` in strict version of `first`

Viewed 78

Why are there two calls to seq in the code below (sourced from here) - r is passed twice:

first' :: (a -> b) -> (a, c) -> (b, c)
first' f (x,y) = let { x' = f x; r = (x', y) } 
                   in x' `seq` r `seq` r

I would think that one call to seq would do the trick of making it strict.

2 Answers

It's a mistake at some level or other. r `seq` r and r are completely identical, semantically.

I'm fairly confident that it is a typo. I guess it should have been

first' :: (a -> b) -> (a, c) -> (b, c)
first' f (x,y) = let { x' = f x; r = (x', y) } 
                   in x' `seq` y `seq` r

so that both pair components are forced. Or perhaps

first' :: (a -> b) -> (a, c) -> (b, c)
first' f (x,y) = let { x' = f x; r = (x', y) } 
                   in x' `seq` r

which produces a fully evaluated pair, assuming that the second component was already evaluated. This is sensible, for instance, if all the operations we use that act on the IORef (Int, Int) state preserve the invariant "both components must always be evaluated".

Related