2013-09-04 6 views
9

Diese Funktion ist falsch und wird nicht kompiliert:Warum kann eine Num nicht mit 0 verglichen werden?

checkIsZero :: (Num a) => a -> String 
checkIsZero a = if a == 0 
        then "Zero" 
        else "Not zero" 

Dies wegen des Vergleichs zwischen a == 0 einem Num und 0 im Ausdruck nicht funktioniert. Das Ändern Num zu Integral macht dies eine gültige Funktion.

Was ist das für eine böse Zauberei, die mich nicht mit 0 vergleicht?!

+0

in GHCI definiert ist es für Num scheint zu funktionieren; verwendest du ghc? Was ist die Fehlermeldung? – jev

+0

Ich setze die obige Funktion in 'functions.hs' dann tue': l functions.hs' in 'ghci' und bekomme den Fehler' Konnte nicht ableiten (Gl. A), der sich aus einer Verwendung von '==' ergibt –

+3

@jev Seit GHC 7.4 sollte es nicht funktionieren, zumindest nicht mit dieser Signatur. 'Eq' wird nicht länger von' Num' impliziert. –

Antwort

23

Num Instanzen erfordert +, *, abs, signum und fromInteger zu implementieren. Beachten Sie, dass == nicht auf der Liste ist! Es sind Instanzen der Eq Typklasse, die == implementieren müssen.

So ist die Num Einschränkung nicht ausreichend - Sie benötigen auch eine Eq Einschränkung. Folgendes wird kompiliert.

checkIsZero :: (Eq a, Num a) => a -> String 
checkIsZero a | a == 0 = "Zero" 
       | otherwise = "Not zero" 

Integral funktioniert, weil etwas, das eine Instanz von Integral ist, muss sich eine Instanz von Ord, was wiederum sein muss eine Instanz von Eq sein.

Sie können alle diese Sachen überprüfen, indem Sie hoogle verwenden und in die Quelle graben.

+0

Kurzer Kommentar - Ich denke, die 'Integral'-Klasse ist ein weiteres Beispiel dafür, dass Haskells numerische Klassen gebrochen sind. Die Idee, die es zu erfassen versucht, ist "Operationen, die mit dem Rest geteilt werden können". In der Mathematik nennen wir das eine "euklidische Domäne" und sie umfasst Objekte wie die Gaußschen Integer, Polynomringe und Potenzreihen, die nicht unbedingt eine sinnvolle 'Ord' Instanz haben und keine Einbettung in die Integer erlauben (so wie es ist) benötigt von 'toInteger'). Ich würde eher eine 'EuclideanDomain'-Klasse und eine separate 'Integral'-Klasse sehen, die z.B. ganze Zahlen Z, und Z/pZ für p prim. –

10

Der Grund für keine Eq Instanz erfordert eine Num Instanz zu definieren, ist, dass es wie

instance Num b => Num (a -> b) where 
    f + g = \x -> f x + g x 
    f - g = \x -> f x - g x 
    f * x = \x -> f x * g x 
    abs f = \x -> abs (f x) 
    signum f = \x -> signum (f x) 
    fromInteger = const . fromInteger 

nützliche Instanzen ausschließen würde, weil Sie ein Eq Beispiel für eine Funktion nicht schreiben können.

+4

Dies gilt nicht nur für solche Funktionsinstanzen, sondern auch für symbolische Algebra-Typen, unendlich genaue Reelle, automatisch abgeleitete Typen ... – leftaroundabout

+2

Ich denke, einige Leute würden mit Ihrer Beschreibung der gegebenen Instanz als "nützlich" argumentieren! –

+5

@BenMillwood Ich würde sagen, diese Leute sind nicht einfallsreich genug. Ein Beispiel für einen Anwendungsfall finden Sie in [this paper] (http://conal.net/papers/beautiful-differentiation/beautiful-differentiation.pdf), in dem eine einfache Methode zur Implementierung der automatischen Differenzierung in Haskell beschrieben wird, die Zeilen wie 'cos enthält = cos>

0

Wenn Daten eine Instanz von Num a sind, ist es kein Empfänger, dass diese Daten eine Instanz von sind.

Integer (und Int, Double) hat beide Instanzen: instance Num Integer und instance Eq Integer und Programm gilt

Integral als

class (Real a, Enum a)=> Integral a where ... 
class (Num a, Ord a)=> Real a where ... 
class Eq a => Ord a where ... 

~= class (Num a, Eq a, Enum a)=> Integral a where ... --means 
+0

Mein 'ghci' sagt, dass' Ord' nicht 'Eq' eine Oberklasse von' Real' ist. –

+0

@Ben Millwood: Danke, du hast Recht. Ich befestige es. – wit

Verwandte Themen