Perhaps you could increase your polynomial type with an index or tag? If I understand correctly, your normal module will be something like this:
data Poly r = Poly r class Ring r where plus :: r -> r -> r times :: r -> r -> r instance Ring (Poly Integer) where plus (Poly x) (Poly y) = Poly (x + y) times (Poly x) (Poly y) = Poly (x * y) gauss :: Poly Integer gauss = Poly 1 eins :: Poly Integer eins = Poly 2
And you want to be able to safely differentiate between the two โsubtypesโ of rings. Perhaps you can mark them like this:
newtype PolyI ir = PolyI r instance Show r => Show (PolyI ir) where show (PolyI p) = show p instance Ring (PolyI i Integer) where plus (PolyI x) (PolyI y) = PolyI (x + y) times (PolyI x) (PolyI y) = PolyI (x * y)
Our Ring instances now require an additional argument of type i , which we can create with the simple no-constructor types.
data Gauss data Eins
Then we just create specific polynomials with an index as an argument:
gaussI :: PolyI Gauss Integer gaussI = PolyI 11 einsI :: PolyI Eins Integer einsI = PolyI 20
With the above instance of Show we get the following result:
*Poly> plus einsI einsI 40
and then
*Poly> plus einsI gaussI Couldn't match expected type `Eins' with actual type `Gauss' Expected type: PolyI Eins Integer Actual type: PolyI Gauss Integer In the second argument of `plus', namely `gaussI'
Is this something like what you were looking for?
Edit: after commenting on the newtype question, I think it can also be an elegant solution if you use NewtypeDeriving to ease the burden of NewtypeDeriving Poly Integer instance. I think in the end it would look like if a little more elegant than this an approach.
ScottWest
source share