Deepseq proposed patch

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` () This is obviously a very broad instance. I believe, for example, that it correctly covers at least every type that is covered by just the instances currently provided in Control.DeepSeq. It also makes it easy to make a new type "deepseq-able" in GHC, as there is an extension which makes Data derivable. I do not believe this instance to be particularly inefficient, although I will grant that there may be types where the NFData instance can force evaluations in a particular order which may be faster than the order chosen by the Data instance. The mechanism is relatively straightforward: The gmapQr is recursively finding all children in the data structure, and creating a long string of seq calls to force each one to be evaluated before finally returning the parent structure. As long as the Data instances don't have "holes" where they skip some children of the structure, this should visit every thunk in the structure and evaluate them all. 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? I'd appreciate your thoughts on this, -Julian Blake Kongslie Please CC me on replies.

On Thu, 10 Jun 2010, Julian Blake Kongslie 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` ()
Is this an instance at all? It is not of the form NFData Type or NFData (TypeCon a) or so.

Henning Thielemann wrote:
On Thu, 10 Jun 2010, Julian Blake Kongslie wrote:
instance (Data a) => NFData a where rnf a = dataDeepSeq a `seq` ()
Is this an instance at all? It is not of the form NFData Type or NFData (TypeCon a) or so.
Writing literally that instance would require the FlexibleInstances and UndecidableInstances extensions, I think, so you're right in that it's not a Haskell98 instance. The point of my email was more that I'm not sure it makes sense to have a "NFData" class, where "Data" would appear to suffice and be easier for programmers to work with. I'm sending this reply to list; not sure what the standard for CCs is on this list. -Julian Blake Kongslie Please CC me on replies.

On 10 June 2010 22:15, Julian Blake Kongslie
The point of my email was more that I'm not sure it makes sense to have a "NFData" class, where "Data" would appear to suffice and be easier for programmers to work with.
Don't Data.Data and traversals through gmapQ etc have a reputation for being particularly slow? (most newer generics libraries benchmark against it to show their swiftness). That seems one good reason against this broad instance. Best wishes Stephen

Stephen Tetley wrote:
Don't Data.Data and traversals through gmapQ etc have a reputation for being particularly slow? (most newer generics libraries benchmark against it to show their swiftness).
That is an excellent point, and one that I hadn't really considered - on profiling, the cases that /I/ care about spend the vast majority of their time actually evaluating thunks rather than in gmapQr, but I don't pretend that I'm a universal case and I'm sympathetic to those with stronger performance needs. -Julian Blake Kongslie Please CC me on replies.

Yes, gmapQ is very slow. This might not matter for forcing mostly
unevaluated data, but for evaluated data it would really hurt.
On Fri, Jun 11, 2010 at 8:20 AM, Stephen Tetley
On 10 June 2010 22:15, Julian Blake Kongslie
wrote: [SNIP] The point of my email was more that I'm not sure it makes sense to have a "NFData" class, where "Data" would appear to suffice and be easier for programmers to work with.
Don't Data.Data and traversals through gmapQ etc have a reputation for being particularly slow? (most newer generics libraries benchmark against it to show their swiftness).
That seems one good reason against this broad instance.
Best wishes
Stephen _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Thu, Jun 10, 2010 at 4:39 PM, Julian Blake Kongslie < jblake@omgwallhack.org> 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` ()
-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
participants (5)
-
Edward Kmett
-
Henning Thielemann
-
Julian Blake Kongslie
-
Lennart Augustsson
-
Stephen Tetley