2013-09-04 20 views
9

Questa funzione non è corretto e non compila:Perché un Num non può essere paragonato a 0?

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

Questo non funziona a causa del confronto tra un Num e 0 nell'espressione a == 0. La modifica di Num a Integral rende questa funzione valida.

Cos'è questa stregoneria malvagia che non mi permette di confrontare i miei numeri con 0?!

+0

in ghci sembra funzionare per Num; stai usando ghc? qual è il messaggio di errore? – jev

+0

Metto la funzione sopra in 'functions.hs', poi eseguo': l functions.hs' in 'ghci' e ottieni l'errore' Impossibile dedurre (Eq a) derivante dall'uso di '==' ' –

+3

@jev Dal momento che GHC 7.4, non dovrebbe funzionare, almeno non con quel tipo di firma. 'Eq' non è più implicito da' Num'. –

risposta

23

Num richiede le istanze di implementare +, *, abs, signum e fromInteger. Si noti che == non è nell'elenco! Sono esempi della classe di caratteri Eq che deve implementare ==.

Quindi, il vincolo Num non è sufficiente - è necessario anche un vincolo Eq. Quanto segue verrà compilato.

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

Integral opere perché qualcosa che è un'istanza di Integral deve essere essa stessa un esempio di Ord, che a sua volta deve essere un'istanza di Eq.

È possibile controllare tutte queste cose utilizzando hoogle e scavando nella fonte.

+0

Commento rapido - Penso che la classe 'Integral' sia un altro esempio di rottura delle classi di tipi numerici di Haskell. La nozione che tenta di catturare è "operazioni che possono essere divise con il resto". In matematica lo chiamiamo "dominio euclideo" e include oggetti come gli interi gaussiani, gli anelli polinomiali e le serie di potenze, che non hanno necessariamente un'istanza "Ord" ragionevole e non ammettono un incorporamento negli interi (come richiesto da 'toInteger'). Preferirei vedere una classe 'EuclideanDomain' e una classe' Integral' separata che potrebbe comprendere ad es. numeri interi Z e Z/pZ per p prime. –

10

Il motivo per cui non richiedono un'istanza Eq per definire un'istanza Num è che esclude le istanze utili come

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 

perché non si può scrivere un'istanza Eq per una funzione.

+4

Questo vale non solo per tali istanze di funzioni, ma anche per i tipi di algebra simbolica, reals di infinito-precisione, tipi derivati ​​automaticamente ... – leftaroundabout

+2

Penso che alcune persone sostengano che la tua descrizione dell'istanza data sia "utile"! –

+5

@ BenMillwood Direi che quelle persone non sono abbastanza fantasiose. Per un esempio di utilizzo, vedere [questo documento] (http://conal.net/papers/beautiful-differentiation/beautiful-differentiation.pdf) che descrive in dettaglio un modo semplice per implementare la differenziazione automatica in Haskell, che include linee come 'cos = cos>

0

Se i dati sono un'istanza di Num a, non è un beneficiario, che questi dati sono un'istanza di Eq a.

Integer (e Int, Double) ha entrambi i casi: instance Num Integer e instance Eq Integer, e il programma è valido

Integral è definito come

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

Il mio 'ghci' dice che' Ord' non 'Eq' è una superclasse di' Real'. –

+0

@ Mill Millwood: grazie, hai ragione. Lo aggiusto. – wit

Problemi correlati