I have declared the following datatype
data Poly a = Poly [a]
and also a class:
class Polynom p where
substitute :: p a -> a -> a
compose :: p a -> p a -> p a
I can make the datatype an instance of the class:
instance Polynom Poly where
substitute = ...
compose = ...
I also want a Ratio
of a Poly
to be an instance of the same class; I have tried many syntaxes and language extensions, but none of them work; things like:
instance Polynom (Ratio . Poly) where ...
-- error: cannot use (.) there
instance Poly p => Polynom (Ratio (p _)) where ...
-- error: no wildcards allowed
type X a = Ratio (Poly x)
instance Polynom X where ...
-- error: X needs another param
instance Polynom (* -> Ratio (Poly *)) where ...
-- error: wrong kind
My goal is to be able to have substitute
and compose
work on a Ratio (Poly *)
; for example:
rf1 = Poly [1,2,3] % Poly [4,5,6] :: Ratio (Poly Int)
rf2 = Poly [0,1] % Poly [1,0] :: Ratio (Poly Int)
rf = rf1 `compose` rf2 :: Ratio (Poly Int)
result = substitute rf 10 :: Int
Is this even possible in Haskell? If so, what syntax or language extension am I missing here?
Update
I solved this using TypeFamilies; as @leftaroundabout suggested. The working class instance looks like this*:
instance Integral a => Polynom (Ratio (Poly a)) where
type Domain (Ratio (Poly a)) = Ratio a
substitute (n :% d) x = substitute ((%1) <$> n) x
/ substitute ((%1) <$> d) x
compose (n :% d) = substitute ((pure <$> n) % (pure <$> d))
*(I actually also changed the bad names; but kept them here to avoid confusion)