[Haskell-cafe] ANN: generic-deepseq

Maxime Henrion mhenrion at gmail.com
Thu Feb 23 23:45:56 CET 2012

On Thu, 2012-02-23 at 23:24 +0100, Bas van Dijk wrote:
> On 23 February 2012 22:09, Maxime Henrion <mhenrion at gmail.com> wrote:
> > On Sun, 2012-02-19 at 21:06 +0100, Bas van Dijk wrote:
> >> On 19 February 2012 18:11, Maxime Henrion <mhenrion at gmail.com> wrote:
> >> > I'm guilty of not having preserved the "rnf :: a -> ()"
> >> > function as the class function though, it's a wrapper around "deepseq"
> >> > in my code. I just didn't see the point of having a class function with
> >> > such a signature versus having a function just like "seq :: a -> b ->
> >> > b". In retrospect, that might have been a bad idea, and maybe I should
> >> > switch to have an "rnf :: a -> ()" class function to make switching even
> >> > easier?
> >>
> >> I'm not sure but maybe a method like "rnf :: a -> ()" is easier to optimize.
> >>
> >> Also in my experience (with generics support in aeson and cereal) it's
> >> a very good idea (performance-wise) to INLINE your methods like I did
> >> in my previous message. Of course the only way to know for sure is the
> >> create some (criterion) benchmarks.
> >
> > Well I wrote some dumb criterion benchmarks that run deepseq over
> > increasingly bigger lists of numbers, and it appears that using rnf as
> > the member function of the DeepSeq class indeed makes a _huge_
> > difference.
> Nice, that's what I expected. Have you checked if adding INLINE
> pragma's helps even more? (I guess not since it's already on par with
> manual written code, as you mentioned)

Oh, I had forgotten to mention that: INLINE pragmas indeed didn't make
any significant difference in my tests, so I let them out.

> BTW I would also recommend making a benchmark for a big sum type.

Yes, I should definitely do that.

> Some nitpicking:
> * In the instance:
> instance GDeepSeq U1 where grnf _ = ()
> I think it makes sense to pattern match on the U1 constructor, as in:
> grnf U1 = ().
> I haven't checked if that's necessary but my fear is that assuming:
> data Unit = Unit deriving Generic; instance DeepSeq Unit
> rnf (⊥ :: Unit) would equal: () while I would expect it to equal ⊥.

That's a good point, I will do tests to see whether this makes a
difference. This seems to mirror my thinking when I asked you whether it
would be safe to skip seq calls in the case the constructor of a type is
strict in another e-mail (have you seen it?).

> * Why do you have the instance:
> instance GDeepSeq V1 where grnf _ = ()
> The only way to construct values of a void type is using ⊥. And I
> would expect that rnf ⊥ = ⊥, not (). I think the best thing is to just
> remove the V1 instance.

This would have the consequence that any type tagged with a phantom type
(for whatever reason) couldn't be used with deepseq, it would return
bottom. What if I want to deepseq a 2-3 finger tree tagged with a
type-level natural that ensures the proper shape of the tree statically?
It seemed to me that I should be able to do that; this is why I added
this V1 instance.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 834 bytes
Desc: This is a digitally signed message part
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20120223/b04cc9cb/attachment.pgp>

More information about the Haskell-Cafe mailing list