Version 1 (modified by diatchki, 8 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.