2015-02-06 13 views
19

Non riesco a capire il seguente comportamento degli intervalli in Haskell. Enumerare 1 a 1 mi dà una lista contenere solo 1 e 2 a 2 mi dà una lista contenere solo 2 come indicato di seguito.Se inserisco [1/0..1/0] su GHCI ricevo Infinito Infinito. Perché?

Prelude> [1..1] 
[1] 
Prelude> [2..2] 
[2] 

Ma enumerazione infinito a infinito mi dà una lista che è infinita di lunghezza e tutti gli elementi sono l'infinito, come illustrato di seguito.

Prelude> [1/0..1/0] 
[Infinity,Infinity,Infinity,Infinity,Infinity,Infinity,Interrupted. 

Sono consapevole del fatto che Infinity è un concetto non deve essere trattato come un numero, ma ciò che giustifica tale comportamento?

+8

Questo è in realtà piuttosto più ragionevole di molte altre conseguenze dei valori dei numeri non reali di IEEE754. – leftaroundabout

risposta

31

di Haskell Double (l'impostazione predefinita che si ottiene quando si utilizza /) segue la IEEE 754 standard per i numeri in virgola mobile, che definisce come si comporta Infinity. Questo è il motivo per cui 1/0 è Infinity.

Con questo standard (e, ad essere onesti, dalla logica), Infinity + 1 == Infinity, e l'istanza per EnumDouble solo aggiunge 1 ogni volta.

Questo è un altro segno che l'istanza Enum per Double non è del tutto ben formata e non è conforme alle aspettative che normalmente abbiamo per le istanze Enum. Quindi, come regola generale, dovresti probabilmente evitare di utilizzare .. per i numeri in virgola mobile: anche se hai capire come funziona, sarà confuso per gli altri che leggono il tuo codice. Come altro esempio di comportamento confusione, prendere in considerazione:

Prelude> [0.1..1] 
[0.1,1.1] 

Se si desidera entrare in molto maggiori dettagli su l'istanza Enum per Double, si può leggere attraverso questo pretty lengthy Haskell-cafe thread.

+0

Mi dispiace per il downvote accidentale. Lo rimuoverò non appena non sarà più bloccato. – Slade

+0

@Slade: Ah, nessun problema. Ho aggiunto un collegamento ad ulteriori letture, quindi il tuo voto non dovrebbe più essere bloccato. –

3

Credo che l'implementazione di [a..b] continui ad aumentare di uno a finché non è maggiore di b. Questo non accadrà mai all'infinito, quindi andrà per sempre.

Credo che il tuo codice sarà probabilmente impostato su Double nel modo in cui lo hai scritto, che ha una semantica ben definita per infinito. IIRC, Haskell segue http://en.wikipedia.org/wiki/IEEE_floating_point.

13

Come Luis Wasserman e Tikhon Jelvis hanno indicato, il problema di fondo è che i Num e Enum istanze per Float e Double sono strano, e in realtà non dovrebbe esistere. In effetti, la classe Enum è piuttosto strana, in quanto tenta di servire diversi scopi contemporaneamente, nessuno di loro bene: probabilmente è meglio considerare un incidente storico e una comodità piuttosto che un buon esempio di come dovrebbe essere una classe di tipografia . Lo stesso è vero, in misura significativa, delle classi Num e Integral. Quando si utilizza una di queste classi, è necessario prestare molta attenzione ai tipi specifici su cui si sta operando.

I metodi per enumFromTo virgola mobile si basano sulla seguente funzione:

numericEnumFromTo :: (Ord a, Fractional a) => a -> a -> [a] 
numericEnumFromTo n m = takeWhile (<= m + 1/2) (numericEnumFrom n) 

Così 2 <= 1+1/2 è falso, ma a causa della stranezza di virgola mobile, infinity <= infinity + 1/2 è vero.

Come indica Tikhon Jelvis, è generalmente preferibile non utilizzare alcun metodo Enum, compresi intervalli numerici, con virgola mobile.

+0

succ. Questo è esattamente il motivo per cui non ci sono 'Enum Double' o' Enum Float' a Frege. – Ingo