2013-07-08 12 views
8

Badam, jak potężne jest przeciążanie funkcji w GHC. Pisałem następujący kod:Dlaczego ta adnotacja typu jest wymagana w Haskell?

class F_third_arg a where 
    run_f :: (Integer, a) -> Integer 

instance F_third_arg Integer where 
    run_f (_, x) = x 

instance F_third_arg String where 
    run_f (x, _) = x 

my_fun :: (F_third_arg a) => Integer -> (a -> Integer) 
my_fun x = \a -> run_f(x, a) 

main :: IO() 
main = putStrLn $ show(((my_fun::Integer->(Integer->Integer)) 5) $ 6) 

(tak, muszę -XTypeSynonymInstances -XFlexibleInstances) i byłem zaskoczony, że kompilator potrzebuje typ adnotacji pobliżu wywołaniu my_fun. Stosuje się do dwóch liczb - na czym polega problem z naniesieniem tej adnotacji? Jakie są zasady przeciążania przy włączonych tych dwóch rozszerzeniach?

+0

"FlexibleInstances" już oznacza "TypeSynonymInstances". 'putStrLn. show' jest równoważne 'print'. I możesz pominąć całkiem sporo paren ... – leftaroundabout

+3

Co do typu ** defaulting ** (oczywiście kompilator nie może _inferować typu: literały liczbowe są polimorficzne!), Nie jestem ekspertem w tym zakresie, ale rozszerzone reguły GHC wykonują zadanie ('{- # LANGUAGE ExtendedDefaultRules # -}' lub GHCi). Lepszym sposobem byłoby "print $ my_fun 5 (6 :: Integer)". – leftaroundabout

+0

Dzięki! Twoje komentarze są naprawdę pomocne. –

Odpowiedz

7

Problem z kodem polega na tym, że liczba literałów jest już przeciążona. Tak więc literalny 6 ma typ Num a => a, natomiast my_fun 5 ma typ F_third_arg b => b -> Integer. Więc podczas wnioskowania o typ, ujednolica te dwie zmienne typu. Ale jak nie ma innych wymagań o nich, GHC nie może znaleźć konkretny typ używania tutaj i daje odpowiedni komunikat o błędzie:

 
test.hs:16:26: 
    No instance for (F_third_arg a0) arising from a use of `my_fun' 
    The type variable `a0' is ambiguous 
    Possible fix: add a type signature that fixes these type variable(s) 
    Note: there are several potential instances: 
     instance F_third_arg String -- Defined at test.hs:9:10 
     instance F_third_arg Integer -- Defined at test.hs:6:10 
    In the expression: (my_fun 5) 
    In the first argument of `show', namely `((my_fun 5) $ 6)' 
    In the second argument of `($)', namely `show ((my_fun 5) $ 6)' 

test.hs:16:38: 
    No instance for (Num a0) arising from the literal `6' 
    The type variable `a0' is ambiguous 
    Possible fix: add a type signature that fixes these type variable(s) 
    Note: there are several potential instances: 
     instance Num Double -- Defined in `GHC.Float' 
     instance Num Float -- Defined in `GHC.Float' 
     instance Integral a => Num (GHC.Real.Ratio a) 
     -- Defined in `GHC.Real' 
     ...plus three others 
    In the second argument of `($)', namely `6' 
    In the first argument of `show', namely `((my_fun 5) $ 6)' 
    In the second argument of `($)', namely `show ((my_fun 5) $ 6)' 

Można by oczekiwać, że kompilator zauważa, że ​​Integer jest jedynym typem, który spełnia zarówno wymagania, ale taka heurystyka spowodowałaby, że twój kod byłby względnie delikatny, tj. zepsułby się tylko dlatego, że dodałeś nową instancję (np. F_third_arg Double). Dlatego kompilator odrzuca kod i prosi użytkownika o jednoznaczne zdanie na temat danego typu.

Znalazłeś jeden sposób, aby to naprawić, ale sugestia @ leftroundabouts użycia 6::Integer jest nieco ładniejsza.

Powiązane problemy