This type can be coerced to ():
newtype Foo = Foo ()
f :: Foo -> ()
f = coerce
But the following cannot:
data Foo = Foo
f :: Foo -> ()
f = coerce -- Fails: Couldn't match representation of type ‘Foo’ with that of ‘()’
GHC says,
• Couldn't match representation of type ‘Foo’ with that of ‘()’
arising from a use of ‘coerce’
• In the expression: coerce
In an equation for ‘f’: f = coerce
|
69 | f = coerce
Is there a way to make that second Foo coercible to ()? They are both isomorphic after all. Failing this, what is the way to automatically create these isomorphisms? For a larger context, see this question (where the constructor's product type is coercible to the NS's type-level list element type).
@Iceland_Jack's suggestion
Trying Jack's suggestion in comments to go via generic Rep:
class (GHC.Generic a, GHC.Generic b, Coercible (GHC.Rep a ()) (GHC.Rep b ())) => HasSameRep a b where
coerceViaRep :: I a -> I b
instance
( Generic a
, Generic b
, Coercible (GHC.Rep a ()) (GHC.Rep b ())
) =>
HasSameRep a b
where
coerceViaRep = I . GHC.to @_ @() . coerce . GHC.from @_ @() . unI
data T = T
proof :: T -> ()
proof = unI . coerceViaRep . I
This fails, however:
src/Ema/Route/Generic/Sub.hs:122:15-26: error:
• Couldn't match representation of type: GHC.U1 @Type ()
with that of: GHC.Rep T ()
arising from a use of ‘coerceViaRep’
• In the first argument of ‘(.)’, namely ‘coerceViaRep’
In the second argument of ‘(.)’, namely ‘coerceViaRep . I’
In the expression: unI . coerceViaRep . I
|
122 | proof = unI . coerceViaRep . I
It doesn't look like the underlying generic representation is in fact equal?