Defining a data type that you do not want to define

I have a Polynomial r data type for polynomials in Haskell and a Ring instance for it. ( class Ring r where plus :: r -> r -> r ; times :: r -> r -> r ; negative :: r -> r ; zero :: r ; one :: r is just a simplified version of Num )

Now I could define a polynomial such as gauss = x^2 + 1 or eisenstein = x^2 + x + 1 , and then work in "Polynomial integer / (gauss)" for Gauss integers or "Polynomial integer / (Eisenstein ) "for Eisenstein integers. In this problem, I wrote it in quotation marks, because it is not a real data type, and I cannot figure out how to define it.

First I tried to do something like data Quotient p = Quot pp , and then, for example, we would have plus (Quot ai) (Quot b i') | i == i' = Quot (plus ab) i plus (Quot ai) (Quot b i') | i == i' = Quot (plus ab) i Of course, this is already pretty bad, but it is not even possible to determine one and zero . So I changed it to data Quotient p = Quot p (Maybe p) , and I think I have a working implementation, but you donโ€™t know if plus will work (it needs at least one Just , and if there are two, then they must be the same).

Is there any type of safe (I mean not using unsafe functions) way to program this in haskell? I'm pretty dumb. Thanks!

+7
source share
2 answers

implicit configurations (cabled here ) uses Z examples as an example; it should be simple to adapt it to polynomial rings (unless I am missing something).

Edit: not to say implicit configurations are simple in themselves, far from it;) - just a modification.

+1
source

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.

+5
source

All Articles