Use "eta-expand" for returned newtypes
Consider
newtype T = MkT (Bool -> Char)
f :: Int -> T
f = \x. ((\y::Bool. blah) |> co)
where co :: (Bool -> Char) ~ T
. Then the simplifer decides that f
has arity 2, and (in SimplUtils.tryEtaExpandRhs
) uses CoreArity.etaExpand
to eta-expand to:
f = (\x y. blah) |> (Int -> co)
We move the cast to the outside, to allow the lambdas to come together. Then Note [Float coercions]
in Simplify.hs will transform to
f2 = \x y. blah
f = f2 |> (Int -> co)
and f will be inlined at every call site. Since the calls may well look like ((f 3) |> co) True
, inlining f = f2 |> (Int->co)
will eliminate a lot of cast clutter.
But this only applies if there is a cast at the top, or in the middle. Suppose the cast was at the end:
newtype N = MkN Int
g :: Int -> N
g = \x -> ...
then we do no eta expansion because g already has manifest arity 1. But it might actually make sense to expand to
g :: Int -> N
g = (\x -> ... |> sym co ) |> (Int -> co)
because then the Note [Float coercions]
in Simplify.hs will transform to
g2 :: Int -> Int
g2 = \x -> ... |> sym co
g :: Int -> N
g = g2 |> (Int -> co)
and now (even if g is recursive) we'll inline g everwhere. That in turn may mean that casts are eliminated.
It also applies for non-functions, with arity zero:
h :: N
h = case <blah> of
True -> 3 |> co -- co :: Int ~ N
False -> 4 |> co
We might want to transform to
h2 :: Int
h2 = (....same code...) |> sym co -- sym co :: N ~ Int
h :: N
h = h2 |> co
It's a simple form of worker/wrapper (as #17673 (closed) observes) but a useful one. I doubt it'll make any programs run faster, but it'll eliminate cast clutter. Moreover, it seems consistent with what we do for other casts.