
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