## GHC doesn't optimize (strict) composition with id

Newtype constructors and selectors have no runtime overhead, but some uses of them do. For example, given `newtype Identity a = Identity { runIdentity :: a }`

, `Identity`

turns into `id`

, but `Identity . f`

turns into `id . f`

, which is distinct from `f`

, because it gets eta-expanded to `\x -> f x`

.

It would be nice to be able to compose a newtype constructor with a function without any overhead. The obvious thing to try is strict composition:

```
(#) :: (b -> c) -> (a -> b) -> a -> c
(#) f g = f `seq` g `seq` \x -> f (g x)
```

In theory this should get rid of the eta-expansion. In practice, the generated Core looks like this:

```
foo :: (a -> b) -> [a] -> [b]
foo f = map (id # f)
-- becomes
foo = \f e -> map (case f of g { __DEFAULT -> \x -> g x }) e
```

Different variations of `(#)`

, and turning `-fpedantic-bottoms`

on, don't seem to affect this. A simpler version, `foo f = map (f`

seq`\x -> f x)`

, generates the same sort of Core.

In one library we resorted to defining a bunch of functions of the form `identityDot :: (a -> b) -> a -> Identity b; identityDot = unsafeCoerce`

. It would be better to be able to rely on GHC to do the optimization directly, if we use strict composition anyway.

## Trac metadata

Trac field | Value |
---|---|

Version | 7.6.1 |

Type | Bug |

TypeOfFailure | OtherFailure |

Priority | normal |

Resolution | Unresolved |

Component | Compiler |

Test case | |

Differential revisions | |

BlockedBy | |

Related | |

Blocking | |

CC | |

Operating system | |

Architecture |