A recent question on Reddit led to discussion of how one might produce a constraint function
type AddUp :: Nat -> Nat -> Nat -> Constraint
-- given
data Nat = Z | S Nat
type family m + n where
'Z + n = n
'S m + n = 'S (m + n)
such that
AddUp m n omeans thatm + n = o.- Any available type information about
m,n, and/orowill flow to the others to the greatest extent possible.
The tricky part is #2, and the trickiest part of that is that if we know, for example, that m ~ 'S x and n ~ 'S ('S y), then we should infer from AddUp m n o that o ~ 'S ('S ('S z)) for some z.
It's quite easy to do this using incoherent instances, as /u/Tarmen showed:
class AddUp m n o
instance {-# INCOHERENT #-} n ~ o => AddUp 'Z n o
instance {-# INCOHERENT #-} m ~ o => AddUp m 'Z o
instance {-# INCOHERENT #-} (o ~ 'S po, AddUp m n po) => AddUp ('S m) n o
instance {-# INCOHERENT #-} (o ~ 'S po, AddUp m n po) => AddUp m ('S n) o
instance {-# INCOHERENT #-} (m ~ 'Z, n ~ 'Z) => AddUp m n 'Z
This particular use of incoherent instances is perfectly safe, but incoherent instances are a rather shady language feature in general. Is it possible to avoid them?