Newtype wrappers

wren ng thornton wren at freegeek.org
Mon Jan 21 05:33:12 CET 2013


On 1/14/13 2:47 PM, Stephen Paul Weber wrote:
> Somebody claiming to be Simon Peyton-Jones wrote:
>>  *   For x1 we can write map MkAge x1 :: [Age]. But this does not
>> follow  the newtype cost model: there will be runtime overhead from
>> executing the  map at runtime, and sharing will be lost too. Could GHC
>> optimise the map  somehow?
>
> My friend pointed out something interesting:
>
> If GHC can know that MkAge is just id (in terms of code, not in terms of
> type), which seems possible, and if the only interesting case is a
> Functor, which seems possible, then a RULE fmap id = id would solve
> this.  No?

The problem is precisely that the types don't line up, so that rule 
won't fire. A more accurate mental model is that when we write:

     newtype Foo = MkFoo { unFoo :: Bar }

the compiler generates the definitions:

     MkFoo :: Bar -> Foo
     MkFoo = unsafeCoerce

     unFoo :: Foo -> Bar
     unFoo = unsafeCoerce

(among others). So the rule we want is:

     fmap unsafeCoerce = unsafeCoerce

Except, there are functions other than fmap which behave specially on 
identity functions. Another major one is (.) where newtypes (but not id) 
introduce an eta-expansion that can ruin performance.

It strikes me that the cleanest solution would be to have GHC explicitly 
distinguish (internally) between "identity" functions and other 
functions, so that it can ensure that it treats all "identity" functions 
equally. Where that equality means rewrite rules using id, special 
optimizations about removing id, etc, all carry over to match on other 
"identity" functions as well.

-- 
Live well,
~wren



More information about the Glasgow-haskell-users mailing list