2012-12-04 24 views
6

Va bene, sto cercando di avvolgere la mia testa intorno a tipeclass, e quindi sto cercando di definire un typeclass per le operazioni geometriche vettoriali. Sono riuscito a farlo funzionare per component-wise +,-,*,/; ma sto lottando con il prodotto dot.Haskell Vector Typeclass: Funzione di [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 

Ovviamente la mia definizione di istanza per la (>.) Non funziona perché il risultato è di tipo Fractional a, non Double.

Ma non so come ottenere questo comportamento dalla dichiarazione nella classe.

quello che avevo come fare è:

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

Ma questo non è valido perché [a] è un tipo e non una variabile di tipo.

Vorrei poterlo spiegare un po 'meglio, ma onestamente non capisco abbastanza da farlo. Speriamo che il codice renderà un po 'più ovvio ciò con cui sto lottando.

+1

Penso che sia necessaria un'altra variabile di tipo per indicare il tipo di scalari, ad esempio 'classe GeomVector a s dove ... (>.) :: a -> a -> s'. – ErikR

+2

Ciò che si desidera è [sinonimi di tipo associato] (http://www.haskell.org/haskellwiki/GHC/Type_families#An_associated_type_synonym_example) – Lambdageek

+0

La dichiarazione della classe è errata non solo a causa del tipo di risultato (>.). Si tenta di produrre un prodotto punto di '' 'u''' e' '' v''' che sono gli elenchi , non le istanze della classe. –

risposta

5

Ecco una possibilità che potrebbe funzionare:

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) 

Così tutti alle istanze del GeomVector avranno una sorta * -> * come la classe Monad. E i tipi di metodi non sono limitati senza necessità ai tipi Fractional solo perché ci si divide da qualche parte lì dentro.

Si potrebbe anche considerare di rendere la classe più piccola possibile (rendere >. una funzione polimorfica al di fuori della classe) e se ciò che si desidera veramente è una classe di caratteri per iniziare. Ma tutto dipende da cosa stai progettando, e non voglio presumere di conoscerlo meglio di te!

+0

Probabilmente non è possibile spostare '> .' fuori dalla classe, poiché è necessario conoscere la struttura interna di ogni istanza di' GeomVector' per fare la somma. – huon

+1

Questo problema può essere risolto aggiungendo un 'toList'. –

+0

giusto, mi dispiace. Quindi una opzione sarebbe quella di rendere la classe 'class (Foldable v) => GeomVector v' se questo ha senso. – jberryman

Problemi correlati