2017-01-21 4 views
0

Ich werde einige grundlegende Implementierungen über typeclass:Automatische Erkennung von Typen bei Verwendung von typeclass-Instanzen?

data Colour = Red | Green | Black 

class BasicEquality a where 
    isEqual :: a -> a -> Bool 

instance BasicEquality Bool where 
    isEqual True True = True 
    isEqual False True = True 
    isEqual True False = True 
    isEqual _ _   = False 

instance BasicEquality Colour where 
    isEqual Red Green = True 
    isEqual _ _   = False 

instance BasicEquality Int where 
    isEqual 100 100  = True 
    isEqual _ _   = False 

main = do 
    print $ isEqual Red Green //Output: True 
    print $ isEqual 100 100 //Output: Error Ambiguous type variable ‘a0’ arising from a use of ‘isEqual’ 

Offensichtlich funktioniert dies, wenn ich print $ isEqual (100 :: Int) (100 :: Int) angeben

Warum Haskell implizit anerkennen, dass Red und GreenColours sind noch verlangt, dass ich speziell 100 zu binden Int?

+0

"Grundgleichheit" ist eine ziemlich seltsame Form der Gleichheit. –

Antwort

3

Red usw. sind monomorphic Werte, dh sie einen konkreten Typ

Red :: Colour 

Also, wenn Red taucht in Ihrem Code haben, weiß der Compiler sofort, welche Art es ist, und es können diese Informationen benutzen, ableiten, welche Typklasseninstanz für z BasicEquality.

OTOH, numerische Literale wie 100 haben die polymorphe Typ Num a => a. Der Grund dafür ist, dass wir

Prelude> replicate 3 'q' 
"qqq" 

sowie

Prelude> sqrt 3 
1.7320508075688772 

Wenn 3 hatte einfach die Art Int, letzteres würde nicht funktionieren, weil sqrt erwartet eine Art von beispielsweise schreiben können, wollen Double. Da numerische Literale tatsächlich polymorph sind, spielt dies keine Rolle.

Das Problem in Ihrem Fall ist, dass auch polymorph ist. Es gibt also mehrere verschiedene Typen, die der Compiler auswählen könnte. Bild, das Sie hatte auch

instance BasicEquality Integer where 
    isEqual 50 1000  = True 
    isEqual _ _   = False 

dann isEqual 100 100 entweder als isEqual (100 :: Int) 100 interpretiert werden könnte (was True) oder isEqual (100 :: Integer) 100 (was falsch ist).

In der Praxis ist dies selten so sehr ein Problem, weil Sie nicht verschiedenen numerischen Literale (diese sind bereits bekannt, so konnte man auch einfach hart Code das Ergebnis!), Aber höchstens Vergleich wird ein Literal mit einer Variablen in Ihrem Programm, und diese Variable wird normalerweise bereits einen Typ haben, der aus dem Kontext bestimmt wird. Zum Beispiel

*Main> let b = length "foobar" 
*Main> isEqual 4 b 
False 

funktioniert ohne jede Unterschrift.

Verwandte Themen