2012-04-29 20 views
13

Pytanie 1Haskell: zrozumienie "No instancji dla" komunikatów o błędach w ghci

Cześć, jeśli w WinGHCi ja celowo zrobić następujące złego kawałek kodu:

3 4 

Następnie komunikat o błędzie I get jest

<interactive>:1:1: 
    No instance for (Num (a0 -> t0)) 
     arising from the literal `3' 
    Possible fix: add an instance declaration for (Num (a0 -> t0)) 
    In the expression: 3 
    In the expression: 3 4 
    In an equation for `it': it = 3 4 

Co dokładnie oznacza No instance for (Num (a0 -> t0))?

Pytanie 2

Dlaczego następujący fragment kodu:

(+) 2 3 4 
<interactive>:1:7: 
    No instance for (Num (a0 -> t0)) 
     arising from the literal `3' 
    Possible fix: add an instance declaration for (Num (a0 -> t0)) 
    In the second argument of `(+)', namely `3' 
    In the expression: (+) 2 3 4 
    In an equation for `it': it = (+) 2 3 4 

dochodowości nieco inny błąd z drugiego kawałka kodu:

2+3 4 
<interactive>:1:3: 
    No instance for (Num (a1 -> a0)) 
     arising from the literal `3' 
    Possible fix: add an instance declaration for (Num (a1 -> a0)) 
    In the expression: 3 
    In the second argument of `(+)', namely `3 4' 
    In the expression: 2 + 3 4 

Mianowicie w pierwszym kawałek kodu mamy No instance for (Num (a0 -> t0)) gdzie jak w drugim kawałku kodu mamy No instance for (Num (a1 -> a0)).


[Response to ehird]

(Pytania przeniesiony z komentarzy odpowiedź):

1) Doceniam te ostatnie dwa wyrażenia są różne, ale mówisz, że nie powinniśmy próbować zrozumieć dlaczego tłumacz wybiera (Num (a0 -> t0)) dla tych pierwszych i (Num(a1 -> a0)) dla tych ostatnich, poza tym, że są one różne?

2) Cześć, a przy pierwszym, gdy mówisz "Ale nie ma instancji Num dla funkcji", co masz na myśli? Niestety, nie jestem pewien, na czym polega koncepcja danej instancji. Co więcej, z czystej ciekawości, mógłbyś użyć metody instancji Num (a -> b), aby jakoś powiedzieć tłumaczowi, aby interpretował 3 4 jako 4 modulo 3?

Odpowiedz

16

Moim zamiarem jest uzupełnienie odpowiedzi ehirda nieco więcej wyjaśnień.Kiedy pisał ekspresję

3 4 

Następnie interpreter Haskell myśli, że próbujesz zastosować funkcję 3 aby cokolwiek 4 jest. W celu Haskell interpretowania 3 jako funkcję, musi nawiązać połączenie z funkcją

fromInteger :: Integer -> (a -> b) 

w celu uzyskania funkcji (czyli coś typu a -> b) z całkowitą 3. Teraz fromInteger jest zdefiniowany w Num typeclass mieć podpis

instance Num x where 
    fromInteger :: Integer -> x 

czyli po dokonaniu typ x instancję klasy Num, dajesz implementację fromInteger który mówi Haskell jak przekonwertować liczbę całkowitą dosłownego do x. W twoim przypadku, x jest typem funkcji a -> b. Więc zróbmy to!


Najpierw część tablicy. Aby x instancją Num Haskell wymaga od nas także sprawiają, że wystąpienie z Show i Eq:

instance Show (a -> b) where show f = "<function>" 
instance Eq (a -> b) where f == g = False 

Teraz powiedzmy, że chcemy interpretować 3 4 jako „4 modulo 3”. Następnie musimy powiedzieć Haskellowi, jak interpretować dowolną liczbę całkowitą jako funkcję, która wywołuje mod. Ponadto, ponieważ mod akceptuje tylko integralne typu (to jest podpis mod :: Integral a => a -> a -> a), wówczas trzeba ograniczyć rodzaje a i b być integralną oraz:

instance (Integral a, Integral b) => Num (a -> b) where 

do make an instance of Num trzeba podać implementacje (+), (-) , (*) i fromIntegral (w rzeczywistości powinniśmy również zdefiniować kilka innych funkcji, ale nie martwmy się tym teraz).

Jest to dość naturalny sposób zdefiniować dodawanie, odejmowanie i mnożenie (cały kod tutaj wpisuje instancji Num i powinny być wcięte w stosunku do deklaracji instancji)

f + g = \x -> f x + g x 
    f - g = \x -> f x - g x 
    f * g = \x -> f x * g x 

czyli po dodaniu dwóch funkcji f i g, otrzymasz nową funkcję, która stosuje zarówno f i g do swojego argumentu, a następnie dodaje je razem. Ponieważ wymagaliśmy, aby wynik zastosowania f i g był typu integralnego, wiemy, że sensowne jest dodawanie ich wyników.

Aby zinterpretować liczbę całkowitą jako funkcji możemy napisać

fromInteger n = \m -> fromIntegral m `mod` fromIntegral n 

czyli gdy mamy całkowitą n wracamy funkcję parametru m, że kiedy nazywa, zapewnia, że ​​oba argumenty są takie same type (przez wywołanie fromIntegral na obu z nich), a następnie używa ich jako argumentów do funkcji mod.

Wreszcie nieco bardziej boilerplate zatrzymać Haskell skarży:

abs f = undefined 
    signum f = undefined 

Możemy przetestować to. Mam swój kod w pliku o nazwie numfun.hs. I uruchomić interpreter Haskell i załadować mój plik:

Prelude> :l numfun.hs 
[1 of 1] Compiling Main    (numfun.hs, interpreted) 
Ok, modules loaded: Main. 

Teraz mogę zdefiniować kilka funkcji:

*Main> let f = (+ 1) 
*Main> let g = (* 2) 

mogę je dodać lub odjąć im:

*Main> (f + g) 3 -- (3+1) + (3*2) 
10 
*Main> (f - g) 3 -- (3+1) - (3*2) 
-2 

i mogę numery telefonów jako funkcje:

*Main> 3 4   -- 4 `mod` 3 
1 
+0

Wow, dziękuję bardzo za to szczegółowe i dobrze opisane wyjaśnienie; Bardzo to doceniam. Myślę, że będę musiał uderzyć w niektóre książki wyszczególnione na stronie Haskell i powrócić do twojego postu jeszcze kilka razy, zanim strawię wszystko, co napisałeś. Dziękuję Ci. – artella

14

Pierwszy błąd występuje, ponieważ liczba całkowita podobna do liczby całkowitej, taka jak 4, może być dowolnego typu z instancją Num. Oznacza to, że 4 ma typ (Num a) => a, dzięki czemu może służyć jako Integer, a Double, a Rational itp Ponieważ zastosowany 3 do argumentu (4), wie, że w kontekście 3 musi być typ funkcyjny (tj. a0 -> t0 dla niektórych a0 i t0). Ale nie ma instancji Num dla funkcji, więc użycie funkcji 3 jako funkcji jest nieprawidłowe. Jeśli dodałeś numer instance Num (a -> b), to by zadziałało, ale prawdopodobnie nie chcesz tego zrobić.

Te dwa komunikaty o błędach są równoważne; nazwy generowane przez GHC nie mają specjalnego znaczenia. Litery są zwykle wyprowadzane ze zmiennych typu w typach funkcji, których używasz, a liczby są dołączane, aby zachować jednoznaczność. W tym przypadku drugie wyrażenie jest równoważne z (+) 2 (3 4) (ponieważ funkcja application wiąże bardziej precyzyjnie niż dowolny operator infiksowania), co nie jest dokładnie takie samo jak pierwszego fragmentu kodu.

+0

Witam, doceniam dwa ostatnie wyrażenia są różne, ale czy nie powinienem próbować zrozumieć, dlaczego tłumacz wybiera "(Num (a0 -> t0))" dla pierwszego i '(Num (a1 -> a0))" dla te drugie, oprócz faktu, że są różne? Dzięki. – artella

+0

Witam, a przy pierwszym, gdy mówisz "Ale nie ma instancji Num dla funkcji", co masz na myśli? Niestety, nie jestem pewien, na czym polega koncepcja danej instancji. Co więcej, z czystej ciekawości, mógłbyś użyć swojej metody 'instance Num (a -> b)', aby jakoś powiedzieć tłumaczowi, żeby interpretował "3 4" jako "4 modulo 3"? Dzięki – artella

Powiązane problemy