How do I make a Constant Applicative Form into, well, not a Constant Applicative Form, to stop it being retained for the lifetime of the program?
I’ve tried this approach:
-- | Dummy parameter to avoid creating a CAF
twoTrues :: () -> [[[Bool]]]
twoTrues _ = map (++ (True : repeat False)) . trueBlock <$> [1..]
but it doesn’t seem to work – the profile shows it as still being retained and still marks it as a CAF.
I’ve found one relevant Google result on this, a reply by Simon Peyton-Jones to Neil Mitchell who asked precisely this question – but that answer refers to a dead link, unfortunately.
Generalise. If you have a constant value, can you generalise this to a function of some variable? The naming of my function in the question,
twoTrues, immediately suggests that this constant is the third in a sequencezeroTrues,oneTrue,twoTrues,threeTruesetc. – and indeed it is. So generalisingtwoTruesinto a functionnTrueswhich takes a parameter n and deletingtwoTrues, would eliminate one CAF from the program.As it happens, in this case, I had only considered the cases
zeroTrues,oneTrueandtwoTruesfor my program because that was all I needed, but my program could naturally be extended to deal withnTruesforn> 2 – so generalising tonTrueswould mean it would make sense to “generalise all the way up” to the users ofzeroTrues,oneTrueetc. That would not always be the case.Note: there might still be other CAFs to deal with, either in the code, or produced by GHC’s “optimisations” (which are not really optimisations in these pathological cases).
This answer may involve more work by the programmer than is strictly necessary, however. It isn’t actually necessary to generalise, as Don’s answer shows.
On the other hand, in some cases, generalising a constant can make it more clear what you are actually doing, and aid reusability. It can even reveal ways to compute a series of values in a better systematic way, and/or more efficiently.
A note about this particular case (which can be ignored): In this particular case, I would not want to make
nTruesitself into an infinite list (which would be a CAF again, reintroducing the original problem!) rather than a function. One reason is that whiletwoTruescould be useful in the form of an infinite list, I can’t see how it would be useful (in my application, anyway) fornTruesto be in the form of an infinite list.