2013-08-06 15 views
6

Próbuję zrozumieć typografie wieloparametrowe, ale po prostu nie otrzymuję deklaracji instancji. Zaczynam próbować utworzyć typeklecie InnerProductSpace dla typu Vector, aby móc wykonać produkt punktowy na dwóch wektorach. Na początek chciałem tylko sprawdzić, czy mogę pomnożyć pierwszy element każdego wektora. Oto mój kodWieloparametrowe deklaracje instancji typu

class InnerProductSpace a b c where 
dot :: a -> b -> c 

data Vector = Vector [Double] 
    deriving (Show) 

instance InnerProductSpace Vector Vector Double where 
    dot (Vector a) (Vector b) = (head a * head b) 

i błąd po próbie użycia funkcji kropka

No instance for (InnerProductSpace Vector Vector c0) 
    arising from a use of `dot' 
The type variable `c0' is ambiguous 
Possible fix: add a type signature that fixes these type variable(s) 
Note: there is a potential instance available: 
    instance InnerProductSpace Vector Vector Double 
    -- Defined at Vector.hs:8:10 
Possible fix: 
    add an instance declaration for 
    (InnerProductSpace Vector Vector c0) 
In the expression: dot a b 
In an equation for `it': it = dot a b 

Co zrobiłem źle? Dzięki!

+6

zajęcia typu Multi-parametrów są pełne koncepcyjnych przeszkód, natomiast rodziny typu działają jak funkcje na poziomie typu, więc są łatwiejsze. Spójrz na moją odpowiedź dla kogoś o podobnym problemie [tutaj] (http: // stackoverflow.com/a/13035800/1598537) i jak sugeruję, aby używały rodzin typów w celu radzenia sobie z przestrzeniami wektorowymi. – AndrewC

Odpowiedz

7

Problem polega na tym, że kompilator nie wie, jak wybrać właściwe wystąpienie, biorąc pod uwagę to, co wie. Jeśli spróbujesz czegoś takiego

vectorA `dot` vectorA 

kompilator idzie poszukiwanie właściwej dot wiedząc, że jego typ musi być dot :: Vector -> Vector -> c0. Niestety, to po prostu za mało informacji samo w sobie - c0 może być cokolwiek, a kompilator nigdy nie zakłada, że ​​tylko dlatego, że ma tylko jedną instancję, musi to być poprawna jedna (jest to związane z założeniem otwartego świata --- tam może będzie kolejną instancją, której kompilator jeszcze nie widział, więc woli po prostu podać błąd). Można uciec z nim jawnie mówi kompilator czego wynikiem powinno być

vectorA `dot` vectorB :: Double 

ale jest to uciążliwe i prawdopodobnie nie wiele z typów liczbowych, ponieważ tak często te typy są uniwersalne, jak również. Na przykład, która instancja Num jest tutaj użyta?

(vectorA `dot` vectorB) + 3 

Wiemy, że to Double, ale kompilator nie może okazać to.

Jednym z rozwiązań jest użycie Typ rodziny jako @AndrewC sugeruje w komentarzu. Naprawdę gorąco to polecam. Innym rozwiązaniem, które zobaczysz na wolności, są Zależności funkcjonalne. Są one napisane jak to

class InnerProductSpace a b c | a b -> c where 
    dot :: a -> b -> c 

i przekłada się pociągać za sobą obietnicę kompilatora: „wiedząc a i b ma wystarczających informacji, aby jednoznacznie zidentyfikować c”. Kompilator zapewnia uczciwość, a także zapobiega pisaniu wystąpień sprzecznych z tą obietnicą.

instance InnerProductSpace Vector Vector Double where 
    dot (Vector a) (Vector b) = (head a * head b) 

instance InnerProductSpace Vector Vector Float where 
    dot (Vector a) (Vector b) = (head a * head b) 

--- 

/Users/tel/tmp/foo.hs:10:10: 
    Functional dependencies conflict between instance declarations: 
     instance InnerProductSpace Vector Vector Double 
     -- Defined at /Users/tel/tmp/foo.hs:10:10 
     instance InnerProductSpace Vector Vector Float 
     -- Defined at /Users/tel/tmp/foo.hs:13:10 

Ale obietnica daje kompilator dokładnie tyle informacji, aby rozwiązać Double w poprzednim przykładzie.

Main*> (Vector [1,2,3]) `dot` (Vector [2,3,4]) + 3.0 
5 
+1

Dzięki! Na razie pozostanę przy zależnościach funkcjonalnych. W tej chwili ma to dla mnie większy sens. To mój pierwszy dzień z Haskellem, więc może jutro będę gotów poradzić sobie z rodzinami typu. ;-) – user2658647

+0

czy to nie oznacza, że ​​aib jest wystarczającą informacją, aby jednoznacznie zidentyfikować c? –

3

lub używają TypeFamilies

class (D a b ~ c) => InnerProductSpace a b c where 
    type D a b 
    dot :: a -> b -> c 

lub

class InnerProductSpace a b where 
    type D a b :: * 
    dot :: a -> b -> D a b 

instance InnerProductSpace Vector Vector where 
    type D Vector Vector = Double 
    dot (Vector a) (Vector b) = (head a * head b) 
Powiązane problemy