More flakiness in RULES involving coerce
Summary
Very basic lambdas in RULES
flake out in the presence of newtype wrappers.
Steps to reproduce
I wrote a function
map# :: (a -> (# b #)) -> Map k a -> Map k b
{-# NOINLINE [1] map# #-}
to see if I can unify the implementations (and rewrite rules) for strict and lazy Map
operations.
L.map, S.map :: (a -> b) -> Map k a -> Map k b
L.map f = map# (\x -> (# f x #))
S.map f = map# (\x -> let !y = f x in (# y #))
{-# INLINABLE L.map #-}
{-# INLINABLE S.map #-}
I added a rule
"mapCoerce" map# (\x -> (# coerce x #))
to see if I could recover L.map coerce = coerce
. To my surprise and delight, this worked! But the story wasn't over.
Because containers
tries to maintain some level of compatibility with non-GHC compilers (particularly to make it not too hard to port to some future Haskell implementation), I didn't want to use unboxed tuples directly. So I did an obvious thing:
newtype SoloU a = SoloU__ (# a #)
pattern SoloU :: a -> SoloU
pattern SoloU a = SoloU__ (# a #)
{-# INLINE SoloU #-}
mapU :: (a -> SoloU b) -> Map k a -> Map k b
{-# NOINLINE [1] mapU #-}
L.map, S.map :: (a -> b) -> Map k a -> Map k b
L.map f = mapU (\x -> SoloU (f x))
S.map f = mapU (\x -> SoloU $! f x)
{-# INLINABLE L.map #-}
{-# INLINABLE S.map #-}
Unfortunately, I couldn't find a way to get a rule to fire. I tried
mapU (\x -> SoloU__ (# coerce x #)) = coerce
mapU (\x -> coerce (# x #)) = coerce
mapU (coerce (\x -> (# x #)) = coerce
but none of those worked.
Expected behavior
I would expect all three of the rules I tried to work.
Environment
- GHC version used: 9.4
Optional:
- Operating System:
- System Architecture: