seq A tuple only makes it evaluate as much as its tuple constructor exposes, but will not evaluate its components.
I.e
let pair = id (1+1, 2+2) in seq pair $ ...
will apply id and produce (_thunk1, _thunk2) , where _thunk indicates additions that are not currently being evaluated.
In your second example, you force the acc battery, but not its components, so some big tricks still accumulate.
You can use the so-called evaluation strategy, for example:
evalPair :: (a,b) -> () evalPair (a,b) = seq a $ seq b () testSeq2 :: Int -> (Int,Int) testSeq2 n = impl n (0,0) where impl 0 acc = acc impl i acc = seq (evalPair acc) $ impl (i-1) ((fst acc)+1, (snd acc)+1)
But then testSeq1 is a simpler approach.
Use strict tuples as another alternative. Such tuples never had a rumble for components, but only the results were evaluated. The forced tuple constructor will also force components as expected.
import Data.Strict.Tuple testSeq2 :: Int -> Pair Int Int testSeq2 n = impl n (0 :!: 0) where impl 0 acc = acc impl i acc = seq acc $ impl (i-1) ((fst acc + 1) :!: (snd acc + 1))
source share