Can fusion see through newtype wrappers?
Asked Answered
S

1

20

Given:

newtype MyVec = MyVec { unVec :: Data.Vector } 
  deriving (Functor, etc)

This will create (something like) this:

instance Functor MyVec where
  fmap f = MyVec . Data.Vector.fmap f . unVec

Will Vectors fusion rules fire and rewrite fmap f . fmap g $ myVec into fmap (f . g) myVec?

Are there any pitfalls I should be aware of? Afaik the problem where you "pay" for new types in containers was solved in GHC 7.8, was it?

Stanislaus answered 19/11, 2014 at 10:16 Comment(0)
U
17

Fusion rules operate on functions, not on types. Your functions on MyVec won't have fusion rules, unless you write them to reuse the underlying ones.

E.g.

map :: (a -> b) -> MyVec a -> MyVec b
map f = MyVec . Vector.map f . unVec
{-# INLINE map #-}

Then we'd have uses:

map f . map g

which will inline to:

MyVec . Vector.map f . unVec . MyVec . Vector.map g . unVec

GHC should then erase the newtype constructor, yielding a regular stream, suitable for fusion:

MyVec . Vector.map f . Vector.map g . unVec

You can confirm this by running GHC and looking at the rewrite rules firing. Alternatively, you can add your own "MyVec. unVec" rewrite rule, but GHC should already cover that.

Underclassman answered 19/11, 2014 at 11:20 Comment(4)
The Haskell wiki states that "newtypes cost nothing". Shouldn't it be reworded if it is indeed the case that they prevent some optimizations?Sideline
Shouldn't the definition of map have a call to MyVec in it, e.g. 'map f x = MyVec $ Vector.map f (unVec x)`?Donkey
First question: how do I find out about the relevant rewrite rules. When I use -ddump-rule-firings I see thousand firings... Which if them are relevant?Stanislaus
Second question: will generic new type derived code be automatically inlined? Else, how do I attach INLINE (or better INLINABLE?) pragmas to derived type classes?Stanislaus

© 2022 - 2024 — McMap. All rights reserved.