2012-12-04 16 views
6

In Ordnung, ich versuche, meinen Kopf um Typklassen zu wickeln, und so versuche ich eine Typklasse für geometrische Vektoroperationen zu definieren. Ich schaffte es, es komponentenmäßig zu funktionieren +,-,*,/;, aber ich kämpfe mit dem Punktprodukt.Haskell Vector Typenklasse: Funktion von [a] -> [a] -> a

class GeomVector a where 
    (>+) :: a -> a -> a 
    (>-) :: a -> a -> a 
    (>*) :: a -> a -> a 
    (>/) :: a -> a -> a 

    (>.) :: a -> a -> Double 

data Vector a = Vec [a] 
       deriving Show 

instance (Fractional a) => GeomVector (Vector a) where 
    (>+) (Vec u) (Vec v) = Vec $ zipWith (+) u v 
    (>-) (Vec u) (Vec v) = Vec $ zipWith (-) u v 
    (>*) (Vec u) (Vec v) = Vec $ zipWith (*) u v 
    (>/) (Vec u) (Vec v) = Vec $ zipWith (/) u v 

    (>.) (Vec u) (Vec v) = sum $ u >* v 

Offensichtlich meine Instanzdefinition für (>.) Wird nicht funktionieren, weil das Ergebnis vom Typ Fractional a, nicht Double.

Aber ich weiß nicht, wie dieses Verhalten von der Deklaration in der Klasse erhalten.

Was würde ich wie zu tun ist:

class GeomVector [a] where 
    (>.) :: [a] -> [a] -> a 

Aber das ist ungültig, weil [a] ein Typ ist und nicht eine Art Variable.

Ich wünschte, ich könnte dies ein wenig besser erklären, aber ich verstehe ehrlich gesagt nicht genug, um dies zu tun. Hoffentlich macht der Code es ein wenig offensichtlicher, mit was ich kämpfe.

+1

Ich denke, dass Sie eine andere Typvariable benötigen, um den Typ der Skalare zu bezeichnen, d. H. 'Klasse GeomVector a s wo ... (>.) :: a -> a -> s'. – ErikR

+2

Was Sie wollen, ist [Synonyme Synonyme] (http://www.haskell.org/haskellwiki/GHC/Type_families#An_associated_type_synonym_example) – Lambdageek

+0

Ihre Klassendeklaration ist nicht nur wegen (>.) Ergebnis Typ fehlerhaft. Sie versuchen, ein Punktprodukt von '' u''' und '' v''' zu erzeugen, die Listen sind, keine Instanzen Ihrer Klasse. –

Antwort

5

Hier ist eine Option, die funktionieren könnte:

class GeomVector v where 
    (>+) :: Num a=> v a -> v a -> v a 
    (>-) :: Num a=> v a -> v a -> v a 
    (>*) :: Num a=> v a -> v a -> v a 
    (>/) :: Fractional a=> v a -> v a -> v a 
    (>.) :: Num a=> v a -> v a -> a 

data Vector a = Vec { vecList :: [a] } 
       deriving Show 

instance GeomVector Vector where 
    (>+) (Vec u) (Vec v) = Vec $ zipWith (+) u v 
    (>-) (Vec u) (Vec v) = Vec $ zipWith (-) u v 
    (>*) (Vec u) (Vec v) = Vec $ zipWith (*) u v 
    (>/) (Vec u) (Vec v) = Vec $ zipWith (/) u v 

    (>.) u v = sum $ vecList (u >* v) 

So alle Ihre Instanzen GeomVector eine Art * -> * wie die Monad Klasse. Und die Arten der Methoden sind nicht unnötig auf Fractional Typen beschränkt, nur weil Sie irgendwo darin teilen.

Sie könnten auch in Betracht ziehen, Ihre Klasse so klein wie möglich zu machen (make >. eine polymorphe Funktion außerhalb der Klasse) und ob Sie wirklich wollen, ist eine Typklasse zu beginnen. Aber alles hängt davon ab, was Sie entwerfen, und ich möchte nicht davon ausgehen, dass ich das besser weiß als Sie!

+0

Es ist wahrscheinlich nicht möglich, '> .' aus der Klasse zu entfernen, da es über die interne Struktur jeder Instanz von' GeomVector' wissen muss, um die Summe zu erstellen. – huon

+1

Dieses Problem könnte durch Hinzufügen einer 'toList' gelöst werden. –

+0

richtig, sorry. Eine Option wäre also, die Klasse "Klasse (faltbar v) => GeomVector v" zu machen, wenn das sinnvoll ist. – jberryman

Verwandte Themen