2010-02-22 10 views
11

Celem tej części kodu jest uczynienie funkcji size bardziej wydajną niż po prostu zliczanie wszystkich elementów w elems. Postanowiłem zsumować dwa typy, które tworzą listę, ale nie mogę stworzyć sygnatury funkcji rozmiaru.W jaki sposób dopasowujesz się do typu "A a b"?

instance (Finite a, Finite b) => Finite (Either a b) where 
    elems = combineLists [Left x | x <- elems] [Right x | x <-elems] 
    size ??? = (size a) + (size b) 

Z Prelude wiemy, że Either a b = Left a | Right b.

Pierwszą rzeczą, którą próbowałem, było dopasowanie Either, ale oczywiście jest to typ, więc to nie działa. Następnie wypróbowałem ((Left a) | (Right b)), ale nie mogę też tego zrobić. Nic innego nie wydaje się pasować do typu Either a b.

udało mi się dostać size (Left a) skompilować, ale ponieważ brakuje składnika b, otrzymuję błąd:

Ambiguous type variable `b' in the constraint: 
    `Finite b' arising from a use of `size' at <interactive>:1:0-12 

co oczywiście ma sens w kontekście, ale naprawdę nie mam pojęcia jak mecz Either a b.

Ktoś ma jakieś myśli?

+1

Wygląda na nieco zakłopotanego różnicą między typem a konstruktorem. "Albo a b" jest typem z dwoma konstruktorami "lewy" i "prawy". Typy przechodzą w sygnaturach typów, podczas gdy konstruktorzy przechodzą kod. Jest to powszechne zamieszanie, ponieważ wiele typów używa tej samej nazwy dla typu i konstruktora, jak w "data Foo = Foo Int String"; pierwszy "Foo" to typ, a drugi to konstruktor. –

Odpowiedz

25

Coś typu Either a b jest albo Left a lub Right b, więc masz dwa przypadki, które mogą być obsługiwane oddzielnie:

size (Left x) = size x 
size (Right x) = size x 

Błąd o zmiennej typu niejednoznacznej jest odrębną kwestią. Po wpisaniu do interpretera czegoś w rodzaju size (Left 1), system nie może wywnioskować, jaka byłaby "właściwa" wartość tej wartości. Może to być Either Int anything i dopóki nie wiadomo, jaki jest typ tego anything, nie można go sprawdzić, jeśli jest w klasie Finite (co jest wymagane przez size).

Można uniknąć tego problemu poprzez określenie wyraźnego typu podpis:

size (Left 1 :: Either Int String) 
0

Problem wydaje się, że trzeba obojętne argument size, ale nie można przejść smoczki dla obu typów a i b w jednym Either a b. Być może można użyć elems uzyskać manekina każdego typu:

size _ = (size . head) (elems :: [a]) + (size . head) (elems :: [b]) 
0

Myślę, że kluczową kwestią masz jest, że chcesz typ, który reprezentuje punkt odniesienia od każdego z dwóch pozostałych typów w tym samym czasie. Either a b może być tylko jednym z a lub b w czasie udzielania.

Prosty typ danych, który reprezentuje zarówno a, jak i b w tym samym czasie, jest 2-krotny.Podpis typ za coś takiego jest (a, b), który jest również wyrażenie tworząc jedną, a więc wzór maching jednego:

> :type (4,5) 
(4,5) :: (Num t, Num t1) => (t, t1) 
> let f (a, b) = 2*a + b 
> f (4,5) 
13 

Należy rozważyć pisząc swoją pierwszą linię z 2-krotki, tak:

instance (Finite a, Finite b) => Finite (a, b) where 

Co oznacza ta Finite (a, b)? Jakie byłyby definicje funkcji członków?

+0

Właściwie już napisałem definicję tego, jest to produkt aib, tworząc mapowanie wszystkich do wszystkich b – Fry

Powiązane problemy