La définition d'un type de données qui ne veut pas définir
Question
J'ai un type de données pour polynomiale r polynômes en Haskell et une instance Anneau pour elle. . (Le class Ring r where plus :: r -> r -> r ; times :: r -> r -> r ; negative :: r -> r ; zero :: r ; one :: r
- c'est juste une version simplifiée du Num)
Maintenant, je pourrais définir un polynôme tel que gauss = x^2 + 1
ou eisenstein = x^2 + x + 1
puis travailler dans « polynomiale Entier / (gauss) » pour les entiers de Gauss ou « polynomiale Entier / (Eisenstein) » pour les entiers d'Eisenstein. C'est le problème, je l'ai écrit entre guillemets parce que ce n'est pas un vrai type de données, et je ne peux pas comprendre comment le définir.
J'ai d'abord essayé de faire quelque chose comme data Quotient p = Quot p p
et par exemple nous aurions plus (Quot a i) (Quot b i') | i == i' = Quot (plus a b) i
Bien sûr, cela est assez mal déjà, mais il est encore impossible de définir one
et zero
. Alors je l'ai changé pour data Quotient p = Quot p (Maybe p)
et je pense avoir une implémentation de travail en utilisant cela, mais vous ne savez jamais sûr si plus
fonctionnera (il a besoin d'au moins un Just
, et s'il y en a deux, ils doivent être les mêmes).
est-il un type sûr (je veux dire ne pas utiliser les fonctions dangereuses) façon de programmer cela dans haskell? Je suis assez perplexe. Merci!
La solution
configurations implicites papier (cabalized ) utilise quotients de Z à titre d'exemple; il devrait être facile de l'adapter à des anneaux polynôme (à moins que je me manque quelque chose).
Modifier: Ne pas dire les configurations implicites se sont simples, loin de là;) - juste la modification
.Autres conseils
Peut-être que vous pourriez augmenter votre type polynôme avec un index ou une étiquette? Si je comprends bien, votre module normale serait quelque chose comme:
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
Et vous voulez être en mesure de différentiel en toute sécurité entre les deux « sous-types » des anneaux. Peut-être que vous pouvez les marquer comme ceci:
newtype PolyI i r = PolyI r
instance Show r => Show (PolyI i r) 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)
Nos instances de l'anneau exigent maintenant un i
type argument supplémentaire que nous pouvons créer en ayant de simples types non-constructeur.
data Gauss
data Eins
Ensuite, nous créons simplement les polynômes spécifiques avec l'index comme argument:
gaussI :: PolyI Gauss Integer
gaussI = PolyI 11
einsI :: PolyI Eins Integer
einsI = PolyI 20
Avec l'instance Show
ci-dessus, nous obtenons le résultat suivant:
*Poly> plus einsI einsI
40
et
*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'
Est-ce quelque chose comme ce que vous cherchez?
Modifier après un commentaire à la question sur newtype
, je pense que cela peut aussi une solution élégante si vous utilisez NewtypeDeriving
pour alléger le fardeau de réimplémenter l'instance Poly Integer
. Je pense à la fin, il serait similaire, si un peu plus élégant que cette approche.