2015-08-25 22 views
5

Przepraszam, że zawracam sobie głowę tym prostym problemem. Próbuję dowiedzieć się, jak działa rozszerzenie rodziny typów. Kiedy się z tym głupio napotkałem błąd, nie mogłem zrozumieć dlaczego.Błąd rodziny typu Haskella

class Foo a b c where 
    data T a b c :: * 

    f :: a -> T a b c 

    g :: T a b c -> b 

    h :: c -> a -> b 
    h c a = g $ f a 

Komunikat o błędzie:

Could not deduce (Foo a b c0) arising from a use of ‘g’ 
from the context (Foo a b c) 
    bound by the class declaration for ‘Foo’ 
    at DB/Internal/Typecast.hs:(17,1)-(25,19) 
The type variable ‘c0’ is ambiguous 
Relevant bindings include 
    a :: a (bound at DB/Internal/Typecast.hs:25:9) 
    h :: c -> a -> b (bound at DB/Internal/Typecast.hs:25:5) 
In the expression: g 
In the expression: g $ f a 
In an equation for ‘h’: h c a = g $ f a 

ja nie rozumiem, jak to c niejednoznaczne w T a b c dla g. Czy kompilator nie może uzyskać typu c z T a b c z f?

Chcę tylko kompozytu g . f

+0

Proszę poprawić wcięcie w przykładowym kodzie - to znaczy zamieścić swój aktualny kod. Kod księgowania inny niż ten, którego używasz, po prostu zaciemnia rzeczywisty problem. – Cubic

+1

"Czy kompilator nie może uzyskać typu' c' z 'T a b c'' f'? Tak, ale skąd 'f' otrzymuje jego' T a b c'? –

+0

@DanielWagner Niestety nie sądzę, że rozumiem, jak działa rodzina typów. Czy T a b c zarówno w f i g, co deklaruję w deklaracji wystąpienia przy użyciu słowa kluczowego danych? – Larry

Odpowiedz

4

Zauważmy, że w definicji

h :: c -> a -> b 
h c a = g $ f a 

nie ma ograniczeń i że fg odnoszą się do samym instancji definiowanej h dla. (A ta elastyczność jest często przydatna do określania instancji).

Od typu wnioskowania, wynik g ogranicza się być tego samego typu b, a argument f ogranicza się być typu a, ale nie ma nic mówiąc, że T a b c przekazywany z jednego do drugiego używa tego samego c!

Aby rozwiązać ten problem, w tym przypadku, można włączyć ScopedTypeVariables i zrobić

h c a = g (f a :: T a b c) 

Zauważ, że to działa, ponieważ rodziny danych są „injective” (argumenty typ rodziny danych można wywnioskować z końcowego typu). Jeśli zamiast tego używałeś rodziny typu, nawet to by nie działało, ponieważ wtedy T a b c niekoniecznie musiałby oznaczać .

Powiązane problemy