2011-01-06 9 views
7

Ich habe einen Datentyp Polynom r für Polynome in Haskell und eine Ring-Instanz dafür. (Die class Ring r where plus :: r -> r -> r ; times :: r -> r -> r ; negative :: r -> r ; zero :: r ; one :: r - es ist nur eine vereinfachte Version von Num).Definieren eines Datentyps, der nicht definiert werden soll

nun ein Polynom wie gauss = x^2 + 1 oder eisenstein = x^2 + x + 1 und arbeiten dann in „Polynomial Integer/(Gauß)“ für die Gaußschen Zahlen oder „Polynomial Integer/(Eisenstein)“ für die Eisen ganzen Zahlen definieren ich konnte. Das ist das Problem, ich habe es in Anführungszeichen geschrieben, weil es kein richtiger Datentyp ist, und ich kann nicht herausfinden, wie man es definiert.

Ich versuchte zunächst so etwas wie data Quotient p = Quot p p und dann zum Beispiel zu tun, würden wir plus (Quot a i) (Quot b i') | i == i' = Quot (plus a b) i Natürlich haben diese schon ziemlich schlecht ist, aber es ist nicht einmal möglich one und zero zu definieren. Also habe ich es in data Quotient p = Quot p (Maybe p) geändert und ich denke, ich habe eine funktionierende Implementierung, die das verwendet, aber Sie nie sicher wissen, ob plus funktioniert (es benötigt mindestens eine Just, und wenn es zwei sind, müssen sie gleich sein).

Gibt es irgendeine Art sicher (ich meine nicht mit unsicheren Funktionen) Weg, dies in Haskell zu programmieren? Ich bin ziemlich ratlos. Vielen Dank!

+0

Ich denke, was Sie wirklich wollen, sind [abhängige Typen] (http://en.wikipedia.org/wiki/Dependent_type) (die in Haskell nicht existieren); Dies würde Ihnen erlauben, etwas wie "Datenquotient (p :: *) (q :: Polynomial r) = Quot p" zu sagen, wobei der Datentyp durch einen Wert parametrisiert wird. Es könnte eine Möglichkeit geben, es in diesem Fall zu emulieren, aber ich bin mir nicht sicher. –

+0

Haben Sie sich das Numeric Prelude, http://hackage.haskell.org/package/numeric-prelude-0.2 angeschaut? Sie haben viel getan, um diese Art von Problemen zu lösen. –

+0

@Antal, ich denke, Ihr 'Quotient' würde funktionieren, wenn Sie für jedes Polynom einen neuen Typ verwenden würden. Klingt jedoch wie ein Schmerz. –

Antwort

1

Das implicit configurations Papier (cabalized here) verwendet Quotienten von Z als ein Beispiel; es sollte einfach sein, es an Polynomringe anzupassen (es sei denn, ich verpasse etwas).

Edit: Nicht implizite Konfigurationen sagen selbst sind einfach, weit davon entfernt;) - nur die Modifikation.

5

Vielleicht könnten Sie Ihren Polynom-Typ mit einem Index oder einem Tag erweitern? Wenn ich es richtig, Ihre normale Modul verstehen wäre so etwas wie:

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 

Und wollen Sie in der Lage sein, sicher der Ringe zwischen den beiden „Untertypen“ Differential. Vielleicht könnten Sie sie markieren, wie so:

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) 

Unsere Instanzen des Rings erfordern jetzt ein zusätzliches Typ-Argument i, die wir durch mit einfachen no-Konstruktor Typen erstellen können.

data Gauss 
data Eins 

Dann schaffen wir nur die spezifischen Polynome mit dem Index als Argument:

gaussI :: PolyI Gauss Integer 
gaussI = PolyI 11 

einsI :: PolyI Eins Integer 
einsI = PolyI 20 

Mit dem Show Beispiel oben, erhalten wir die folgende Ausgabe:

*Poly> plus einsI einsI 
40 

und dann

*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' 

Ist das etwas, wonach Sie gesucht haben?

Edit: nach einem Kommentar auf die Frage nach newtype, ich denke, dies kann auch eine elegante Lösung, wenn Sie NewtypeDeriving verwenden, um die Last der Neuimplementierung die Poly Integer Instanz zu erleichtern. Ich denke, am Ende wäre es ähnlich, wenn auch etwas eleganter als dieser Ansatz.

+0

ansehen PolyI 'als' Daten PolyI ir = PolyI r Ableitung Show ', auf Kosten von Typ-Signaturen (PolyI 3 :: PolyI Gauß Integer'). –

+0

Ah, das ist wahr. In dieser Situation könnte man sogar eine einfache Funktion dafür definieren ('polyIGauss :: Integer -> PolyI Gauß Integer', ebenfalls für' Eins'), um zu vermeiden, dass die möglicherweise langen Signaturen viele Male eingegeben werden müssen. – ScottWest

+0

Es ist nicht notwendig, dieses undefined Geschäft zu machen: nur 'newtype PolyI i r = PolyI r 'und' gaussI :: PolyI Gauß Integer; gaussI = PolyI 11'. Dann verstecken Sie den 'PolyI'-Konstruktor. – luqui

Verwandte Themen