Deepseq proposed patch

Edward Kmett ekmett at
Mon Jun 14 10:01:50 EDT 2010

On Thu, Jun 10, 2010 at 4:39 PM, Julian Blake Kongslie <
jblake at> wrote:

> Control.DeepSeq has a large number of instances for its class NFData,
> I'd like to propose a new one:
> import Data.Data
> dataDeepSeq :: (Data a) => a -> a
> dataDeepSeq a = gmapQr ($) a (seq . dataDeepSeq) a
> instance (Data a) => NFData a where
>  rnf a = dataDeepSeq a `seq` ()


The problem with this instance is that it is not well behaved. In fact it
precludes, without the particularly evil extension OverlappingInstances, any
other NFData instances from being specified.

Type class resolution relies on pattern matching on the instance head, and
flows backwards across the =>, without backtracking. So upon seeing this
instance, whenever the compiler sees an NFData constraint, it'll likely
reach for this instance first, and go hunting for a Data instance which may
or may not exist.

> Of course, this raises an interesting point: Are there types which can
> be reasonably made NFData instances, but not Data instances, or for
> which the NFData instance can be made significantly better in some way?

Yes. There are many. Consider any Data instance that deliberately prevents
introspection, such as those for most of the 'containers' library. The new
instance would cause NFData to just flat out break for those data types.

You _can_ define an instance like this, but you need to wrap it in a newtype
to avoid subsuming all other instance heads.

newtype NF a = NF a deriving (Data, Typeable)

instance Data a => NFData (NF a) where
   rnf a = dataDeepSeq a `seq` ()

Then to opt in to its use you need to manually wrap and unwrap your type
with it.

-Edward Kmett
-------------- next part --------------
An HTML attachment was scrubbed...

More information about the Libraries mailing list