Lets look at a typical bit of generated happy code (without using --coerce):
happyReduce_1 = happySpecReduce_2 17 happyReduction_1
happyReduction_1 (HappyAbsSyn_2 happy_var2) (HappyAbsSyn_1 happy_var1) =
HappyAbsSyn_3 (foobar happy_var1 happy_var2)
So the crucial question is: does the result of foobar above get reduced to weak head normal form?
The answer is no. Therefore the title of the issue: this is insufficiently strict.
It's also contrary to what the user guide says.
This option causes the right hand side of each production (the semantic value) to be evaluated eagerly at the moment the production is reduced. If the lazy behaviour is not required, then using this option will improve performance and may reduce space leaks.
Lets see why it is not strict...
happySpecReduce_2 nt fd ... =
let r = fn v1 v2
in happySeq r ...
Ok, so in --strict mode happySeq = seq and so it does reduce fn v1 v2 to WHNF. But what is fn in practice? In the (typical) example above it is
HappyAbsSyn_3 (foobar happy_var1 happy_var2)
which is already in WHNF! So this does nothing. And crucially it does not reduce foobar to WHNF.
Why not? Because HappyAbsSyn_3 itself is a constructor with a single non-strict field:
data HappyAbsSyn t1 t2 t3 = ... | HappyAbsSyn_1 t1 | HappyAbsSyn_2 ts | HappyAbsSyn_3 t3
So perhaps the fix is simple: make the HappyAbsSyn_X constructors have strict fields?
Presumably at some point in happy's history this strict mode did actually do something, but I'm guessing some change later introduced the non-strict HappyAbsSyn constructors and foiled the strictness. Maybe?
On the other hand the --coerce mode, when combined with --strict does look like it will actually be strict. Since in this mode the non-strict HappyAbsSyn_X constructors are replaced by very-much-strict unsafeCoerce# "functions". In one real world parser, comparing --strict --ghc vs --strict --ghc --coerce nets substantial memory reductions. And previously ghc-debug's thunk analysis showed that there were huge numbers of thunks originating from the generated reduction functions.
Lets look at a typical bit of generated happy code (without using
--coerce):So the crucial question is: does the result of
foobarabove get reduced to weak head normal form?The answer is no. Therefore the title of the issue: this is insufficiently strict.
It's also contrary to what the user guide says.
Lets see why it is not strict...
Ok, so in
--strictmodehappySeq = seqand so it does reducefn v1 v2to WHNF. But what isfnin practice? In the (typical) example above it iswhich is already in WHNF! So this does nothing. And crucially it does not reduce
foobarto WHNF.Why not? Because
HappyAbsSyn_3itself is a constructor with a single non-strict field:So perhaps the fix is simple: make the
HappyAbsSyn_Xconstructors have strict fields?Presumably at some point in happy's history this strict mode did actually do something, but I'm guessing some change later introduced the non-strict
HappyAbsSynconstructors and foiled the strictness. Maybe?On the other hand the
--coercemode, when combined with--strictdoes look like it will actually be strict. Since in this mode the non-strictHappyAbsSyn_Xconstructors are replaced by very-much-strictunsafeCoerce#"functions". In one real world parser, comparing--strict --ghcvs--strict --ghc --coercenets substantial memory reductions. And previouslyghc-debug's thunk analysis showed that there were huge numbers of thunks originating from the generated reduction functions.