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` ()
-1
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