2017-02-02 5 views
0

Dies ist ein Follow-up zu this question, aber das Problem ist etwas anders in Anwendung und Grund, so entschied ich mich, eine neue Frage zu stellen.Simplfying Art durch Fixieren Parameter

Betrachten diese Definitionen (edit: dieser Teil einer externen Bibliothek sind):

class (Num a, Cast a b, Cast b a, Storable b, Code b) => Elem a b | a -> b where 

data Matrix a b where 
    Matrix :: Elem a b => !Int -> !Int -> !(Vector b) -> Matrix a b 

instance Elem Float CFloat where 
instance Elem Double CDouble where 
instance Elem (Complex Float) (CComplex CFloat) where 
instance Elem (Complex Double) (CComplex CDouble) where 

In anderen Worten, eine Gleitkomma-Matrix mit darunter liegenden C-Typ "fixed" durch die funktionale Abhängigkeit Elem.

Jetzt, um einige Instanzen für bestimmte Container spezifische Klassen zu implementieren (in meinem speziellen Fall für die Lookup Klasse, aber Ixed von Linse könnte ein anderer Kandidat sein) Ich brauche einen Matrix-Typ mit einem Typ Parameter.

Ich habe versucht, die folgenden:

type family CType a where 
    CType Double = CDouble 
    CType Float = CFloat 
    CType (Complex Double) = (CComplex CDouble) 
    CType (Complex Float) = (CComplex CFloat) 

newtype MatX a = MatX { getMatX :: Matrix a (CType a) } 

Bitte beachte, dass ich nicht einfach erlaubt bin, das „b“ Art in der newtype Erklärung wegzulassen, so dass die Art Synonym als Mittel dient dazu, die interne Art zu beheben.

jedoch alle Funktionen auf dem Matrix-Typ haben Typen wie

(Elem a b) => Matrix a b -> some -> other -> params -> result 

Als Beispiel wird die unsafeCoeff Funktion wie folgt aussieht:

unsafeCoeff :: Elem a b => Int -> Int -> Matrix a b -> a 
unsafeCoeff row col (Matrix rows _ vals) = cast $ Data.Vector.Storable.unsafeIndex vals $ col * rows + row 

mit dieser Art mATX wie zum Beispiel:

instance Lookup MatX where 
    lookup (i,j) m = Just $ unsafeCoeff i j (getMatX m) 

gibt mir den Fehler "Keine Instanz für (Elem a (CType a))". Da ich diese Instanzen nicht angeben darf (da Typ-Synonyme in Instanz-Deklarationen nicht erlaubt sind) bin ich an dieser Stelle irgendwie festgefahren. Ich sehe, warum der Compiler nicht annehmen kann, dass Elem a (CType a) tatsächlich gegeben ist, aber ich weiß nicht, wie ich diese Beziehung spezifizieren soll.

Bonus:

Ich habe auch versucht, nur dies zu tun:

instance Lookup (Matrix a) where 
    lookup (i,j) m = Just $ unsafeCoeff i j m :: Maybe a 

Aber dann "b" ist der Elementtyp des Behälters und die Lookup-Funktion muss zurückkehren (die nicht näher bezeichnet) b.

Edit: Die Vollständigkeit halber die Definition Lookup aus dem obigen Link:

type family Key f 

class Lookup f where 
    lookup :: Key f -> f a -> Maybe a 
+0

Was ist die Definition der Klasse 'Lookup'? –

+0

@ReidBarton: Ich habe am Ende der Frage hinzugefügt. –

+0

Wenn eine 'Matrix' eine 'Elem a b'-Bedingung enthält, warum benötigen die Operationen in' Matrix' auch einen 'Elem a b' Kontext? –

Antwort

2

sollten Sie in der Lage sein

type instance Key MatX = (Int, Int) 
instance Lookup MatX where 
    lookup (i,j) (MatX [email protected](Matrix {})) = Just $ unsafeCoeff i j m 

Muster auf die Anpassung zu schreiben Matrix Konstruktor bringt die Elem a b Einschränkung, die es enthält, in den Gültigkeitsbereich. (Es ist seltsam, dass die eigen Bibliothek macht Sie dies aber tun, da es sowieso auf dem Matrix Konstruktor übereinstimmen muss.)


Edited zu mehr Erklärung hinzuzufügen. Die Definition von lookup oben ist ein kürzerer Weg

lookup (i,j) (MatX m) = case m of 
    Matrix _ _ _ -> Just $ unsafeCoeff i j m 

für den Mustervergleich zu schreiben, siehe section 3.17 des Haskell-Berichts. Die Musterübereinstimmung auf Matrix sieht nutzlos aus, da sie keine Variablen bindet; aber es bindet unsichtbar eine Elem Einschränkung, die in dem Aufruf an unsafeCoeff verwendet wird.

+0

Das funktioniert. Wusste nicht einmal, dass ich Muster auf einem Konstruktor in einem Aliasmuster abgleichen kann (wenn das hier passiert). Wo lernt man solche Tricks? Alle Bücher, die ich gefunden habe, sind nur eine weitere Erklärung für Monaden ... Arbeitet und verbessert mein Verständnis, so akzeptiert. –

0

Der Compiler immer schlägt nicht den richtigen Hinweis, aber in diesem Fall, wenn es No instance for (Elem a (CType a)) sagt, es wirklich bedeutet Das. Sie haben die Einschränkung Elem a b angegeben, wobei b durch das erste Argument der Funktion bestimmt wird. Sie müssen jedoch etwas aufrufen, das b ~ CType a erfordert. Dies kann der Compiler nicht herausfinden. Sie müssen den Typ Ihrer Funktion auf Matrix a (CType a) -> some -> other -> params -> result beschränken und die Einschränkung Elem a b in Elem a (CType a) ändern.

Es könnte praktisch sein Synonyme für diese zu definieren:

type CMatrix a = Matrix a (CType a) 
type CElem = (Elem a (CType a)) -- requires -XConstraintSynonyms 

Eine noch bessere Alternative könnte die funktionale Abhängigkeit von Elem zu entfernen, wenn Sie immer für b ~ CType a beabsichtigen. Auch wenn Sie nicht immer b ~ CType a möchten, können Sie immer noch die funktionale Abhängigkeit entfernen und CType eine zugehörige Art von Elem machen:

class (Num a, Cast a (ElemType a), Cast (ElemType a) a, Storable (ElemType a), Code (ElemType a)) => Elem a where 
    type ElemType a 
    ... 
+0

Ich hätte darauf hinweisen sollen, dass Matrix und Elem Teil der Haskell-Eigen-Bibliothek sind. Ich habe diese Bibliothek stark modifiziert, um einige Statusfehler herauszufiltern, aber die Änderung dieser Einschränkungen würde zu einer vollständigen Neuschreibung der Bibliothek führen. –