|Version 1 (modified by diatchki, 10 years ago) (diff)|
- It provides a mechanism to allow an effective, systematic tracking down of a class of space leaks.
- It provides a mechanism to simply stomp on a class of space leaks.
- It avoids the user having to explicitly declare instances for a homebrew deepSeq for every type in your program.
- It has a declarative feel; this expression is hyper strict.
- Is a specification of strictness.
- It will open up various optimization opportunities, avoiding building thunks. (I dont talk about this more, but I'm happy to elaborate)
- It can have an efficient implementation, or a simple (slow) implementation. (The fast implementation one can be used to stomp space leaks, the slow one can help find the same leaks.)
- We can ensure that there are no exceptions hiding inside a data structure.
- We can throw an exception, and know that there are no exceptions hidding inside it. (are there exceptions in Haskell'?)
What is being proposes for Haskell' are four things:
Add a strict function into Haskell'
strict :: a -> a
- I do not really care if its in a class or not; would prefer not for the reasons John Hughes talked about.
- This would Deep Seq all its children for regular constructors.
- strict would not indirect into IO or MVar.
- functions would be evaluated to (W?)HNF.
- IO, ST are functions under the hood for the purpose of strict.
Add a $!! function, and a deepSeq function
f $!! a = strict a `seq` f a deepSeq a b = strict a `seq` b
We use strict as our primitive, rather than deepSeq. The expressions (x deepSeq y deepSeq z) and (strict x seq strict y seq z) are equivalent, but only the latter makes it clear that z doesn't get fully evaluated.
Add a !! notation, where we have ! in datatypes.
data StrictList a = Cons (!!a) (!!StrictList a) | Nil
Add a way of making *all* the fields strict/hyperstrict.
data !!StrictList a = ..
We could also do this for !
strict :: a -> a strict a@(RAW_CONS <is_deep_seq'd_bit> ... fields )) = if <is_deep_seq'd_bit> == True then return a /* hey, we've already deepSeq'd this */ else do strict# (field_1) strict# (field_2) ... strict# (field_N) /* we set the test bit after the recursive calls */ set <is_deep_seq'd_bit> to True. return a strict a@(REF/MVAR...) = return a
We check the deep_seq'd but *after* evaluating children.
- This Stops the (mis)use of strict to observe cycles.
- With this order, we do not need to catch exceptions.
- Should there be a DeepSeq? class?
- Perhaps have an unsafeStrict :: a → IO a, that tags the deep_seq'd bit when descending.
- What would you expect to happen here?
f x xs = let g y = x+y in map !! g xs
Here I'm evaluating the function g hyperstrictly before the call
to map. Does x, the free variable in g's function closure, get evaluated?
- Should we have the property strict g === strict . g . strict
- Another option would be for the DeepSeq? class (or whatver) have a depth limited version,
deepSeqSome :: DeepSeq a => Int -> a -> a
which would only traverse a limited depth into a structure.