2016-08-01 14 views
3

Ich sehe, dass Haskell verschiedene numerische Typen verglichen werden können:Wie funktioniert die Gleichheit für numerische Typen?

*Main> :t 3 
3 :: Num t => t 
*Main> :t 3.0 
3.0 :: Fractional t => t 
*Main> 3 == 3.0 
True 

Wo ist der Quellcode für die Eq Instanz für numerische Typen? Wenn ich einen neuen Typ wie ComplexNumber erstelle, kann ich == erweitern, um dafür zu arbeiten? (Ich möchte vielleicht, dass komplexe Zahlen ohne Imaginärteile möglicherweise reellen Zahlen entsprechen.)

+2

Dies ist nur ein Beispiel für (erweiterte?) Standardregeln in GHCi. – crockeea

+4

Ein vielleicht verwirrender Punkt hier: obwohl '3' und' 3.0' unterschiedliche polymorphe Typen haben, im Ausdruck '3 == 3.0 ', erhalten beide den gleichen monomorphen Typ, bevor die Gleichheit berechnet wird. Der Typ von '(==)' besagt, dass er zwei Argumente des gleichen Typs akzeptieren muss: 'Eq a => a -> a -> Bool '. Ich vermute, dass Missverständnisse diese Subtilität zu der Frage führen. –

+1

"ermöglicht den Vergleich verschiedener numerischer Typen". Probieren Sie es aus: 'length" abc "== 3.0'. Funktioniert es? –

Antwort

10

"Haskell erlaubt das Vergleichen verschiedener numerischer Typen" nein, tut es nicht. Was Haskell tatsächlich zulässt, sind verschiedene Typen, die durch dieselben Literale definiert werden. Insbesondere können Sie tun

Prelude> let a = 3.7 :: Double 
Prelude> let b = 1 :: Double 
Prelude> a + b 
4.7 

OTOH, wenn ich diese explizit mit widersprüchlichen Typen deklariert, würde die Zugabe fehlschlagen:

Prelude> let a = 3.7 :: Double 
Prelude> let b = 1 :: Int 
Prelude> a + b 

<interactive>:31:5: 
    Couldn't match expected type ‘Double’ with actual type ‘Int’ 
    In the second argument of ‘(+)’, namely ‘b’ 
    In the expression: a + b 

Nun Double ist nicht die allgemeinste mögliche Art für entweder a oder b. Tatsächlich sind alle Zahlenliterale polymorph, aber bevor irgendeine Operation (wie Gleichheitsvergleich) stattfindet, muss ein solcher polymorpher Typ auf eine konkrete monomorphe Art festgelegt werden. Wie,

Prelude> (3.0 :: Double) == (3 :: Double) 
True 

Weil ==, im Gegensatz zu Ihrer Prämisse, erfordert tatsächlich beide Seiten die gleiche Art haben, können Sie die Unterschrift auf beiden Seiten auslassen ohne etwas zu ändern:

Prelude> 3.0 == (3 :: Double) 
True 

In der Tat, auch ohne irgendeine Art Anmerkung, GHCi behandelt immer noch beide Seiten als Double. Dies liegt an type defaulting - in diesem speziellen Fall ist Fractional die stärkste Einschränkung für den Typ mit gemeinsam genutzter Nummer, und für Fractional ist der Standardtyp Double. OTOH, wenn beide Seiten integrale Literale gewesen wären, dann hätte GHCi Integer gewählt. Dies kann manchmal einen Unterschied machen, zum Beispiel

Prelude> 10000000000000000 == 10000000000000001 
False 

aber

Prelude> 10000000000000000 ==(10000000000000001 :: Double) 
True 

weil im letzteren Fall wird die endgültigen 1 in den Floating-Point-Fehlern verloren.

+0

Danke. Also wäre ich nicht in der Lage, die Gleichheit von Elementen eines neuen Typs, den ich erstellt habe, zu testen? –

+2

Nicht von bereits existierenden Typen, nein. Und nicht einmal zu anderen Typen, die du auch erstellt hast. Sie können nur den Typ "a" mit dem Typ "a" vergleichen. –

+1

@espertus: Sie können problemlos zwei Werte eines neuen Typs, die Sie selbst erstellt haben, vergleichen. Schreiben Sie einfach eine ['Eq'] (http://hackage.haskell.org/package/base-4.9.0.0/docs/Prelude.html#t:Eq) Instanz für diesen Typ. – leftaroundabout

2

Hier ist nichts Magisches. 3 kann entweder eine reelle Zahl oder eine ganze Zahl sein, aber sein Typ wird mit einer reellen Zahl im Vergleich zu 3.0 vereinheitlicht.

Beachten Sie die Typenklasse:

class Eq a where 
    eq :: a -> a -> Bool 

So eq wirklich nur, dass die Dinge gleichen Typs vergleichen. Und Ihr Beispiel 3 == 3.0 bekommt seine Typen vereinheitlicht und wird 3.0 == 3.0 intern.

Ich bin nicht sicher, irgendwelche Art Tricks, um es mit einem benutzerdefinierten komplexen Zahl Typ vereinheitlichen. Mein Bauchgefühl sagt mir, dass es nicht getan werden kann.

+0

Nein. Es kann getan werden. Überprüfen Sie dies: https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-790004.3.4 Nun, wenn dieser Standard-Mechanismus allgemeiner wäre, wäre ich glücklicher ... – Alec