Qual è la differenza tra non definito in Haskell e nulla in Java?
Domanda
Entrambi sono termini il cui tipo è l'intersezione di tutti i tipi (disabitata). Entrambi possono essere passati in giro nel codice senza fallire fino a quando uno tenta di valutare loro. L'unica differenza che posso vedere è che in Java, v'è una lacuna che consente null
da valutare esattamente per un funzionamento, che è confronto di uguaglianza riferimento (==
) - mentre in Haskell undefined
non può essere valutato affatto senza restituire eccezione. È questa l'unica differenza?
Modifica
Quello che sto veramente cercando di arrivare con questa domanda è, perché è stato compreso null
in Java una decisione così apparentemente povera, e come Haskell fuggire esso? Mi sembra che il vero problema è che si può fare qualcosa di utile con null
, ovvero è possibile controllare la presenza di nullness . Perché si è permesso di fare questo, è diventato convenzione standard per passare attorno a valori nulli nel codice e li hanno indicano "nessun risultato" invece di "v'è un errore logico in questo programma". Mentre in Haskell, non c'è modo di controllare se un Esamina termine verso il basso senza valutare e il programma di esplodere, in modo che possa mai essere utilizzato in modo tale per indicare "nessun risultato". Invece, si è costretti a utilizzare qualcosa come Maybe
.
Scusate se sembra che sto giocando a tira e molla con il termine "valutare" ... Sto cercando di tracciare un'analogia qui e problemi fraseggio con precisione. Direi che è un segno che l'analogia è imprecisa.
Soluzione
Qual è la differenza tra undefined in Haskell e nulla in Java?
Ok, facciamo di nuovo un po '.
"indefinito" in Haskell è un esempio di un valore "basso" (indicato ?). Tale valore rappresenta uno stato indefinito, bloccato o parziale nel programma.
Molte diverse forme di fondo esistono: loop non fatale, eccezioni, Pattern Match fallimenti - in pratica qualsiasi stato nel programma che non è definita in un certo senso. Il valore undefined :: a
è un esempio canonico di un valore che mette il programma in uno stato indefinito.
undefined
sé non è particolarmente speciale - non è cablato in - ed è possibile implementare undefined
Haskell utilizzando qualsiasi espressione in basso rendimento. Per esempio. questa è una valida implementazione di undefined
:
> undefined = undefined
o uscire immediatamente (il vecchio compilatore Gofer usato questa definizione):
> undefined | False = undefined
La proprietà principale di fondo è che se un'espressione restituisce il basso, l'intero programma valuteranno in basso:. Il programma è in uno stato indefinito
Perché si vuole un tale valore? Beh, in un linguaggio pigro, spesso è possibile manipolare le strutture o le funzioni che memorizzano i valori di fondo, senza il programma stesso essere inferiore.
es. un elenco di cicli infiniti è perfettamente cromulent:
> let xs = [ let f = f in f
, let g n = g (n+1) in g 0
]
> :t xs
xs :: [t]
> length xs
2
Ho appena non può fare molto con gli elementi della lista:
> head xs
^CInterrupted.
Questa manipolazione di roba infinita è parte del motivo per cui così divertente e di Haskell espressiva. Un risultato di pigrizia è Haskell presta particolare attenzione ai valori bottom
.
Tuttavia, chiaramente, il concetto di fondo si applica altrettanto bene a Java, o qualsiasi altro linguaggio (non totale). In Java, ci sono molte espressioni che valori di rendimento "fondo":
- confrontando un riferimento rispetto nullo (se nota, non
null
stesso, che è ben definita); - divisione per zero;
- out-of-bounds eccezioni;
- un ciclo infinito, ecc.
È solo che non hanno la capacità di sostituire un fondo per un altro molto facilmente, e il compilatore Java non fa molto per ragionare su valori inferiori. Tuttavia, tali valori ci sono.
In sintesi,
- dereferencing un valore
null
in Java è un'espressione specifica che produce un valore di fondo in Java; - il valore
undefined
in Haskell è un generico espressione inferiore rendimento che può essere utilizzato ovunque un valore inferiore è richiesto in Haskell.
E 'così che sono simili.
Postscript
Per quanto riguarda la questione del null
stessa:? Il motivo per cui è considerato cattiva forma
- In primo luogo,
null
di Java è sostanzialmente equivalente a aggiungendo unMaybe a
implicito ad ogni tipoa
in Haskell . - Dereferenziare
null
equivale a pattern matching per solo il casoJust
:f (Just a) = ... a ...
Così, quando il valore passato è Nothing
(in Haskell), o null
(in Java), il programma raggiunge uno stato indefinito. Questo è un male:. Vostro programma si blocca
Quindi, con l'aggiunta di null
a tutti tipo, hai appena reso molto più facile creare valori bottom
per caso - i tipi più aiuto. Il tuo linguaggio non è più sta aiutando a prevenire quel particolare tipo di errore, e questo è male.
Naturalmente, gli altri valori di fondo sono ancora lì: eccezioni (come undefined
), o cicli infiniti. Aggiunta di una nuova modalità di guasto possibile ad ogni funzione - dereferenziazione null
- rende solo più facile scrivere programmi che si scontrano
Altri suggerimenti
La tua descrizione non è del tutto corretto. Stai dicendo null
non può essere valutato. Tuttavia dal momento che Java è un linguaggio ansioso, ciò significherebbe che f(null)
getterebbe un NPE non importa quale sia la definizione di f
è (perché il metodo argomenti sono sempre valutate prima dell'esecuzione del metodo).
L'unica ragione che è possibile passare in giro undefined
in Haskell senza ottenere un'eccezione è che Haskell è pigro e non valuta gli argomenti meno necessari.
Una ulteriore differenza tra indefinito e nulla è che undefined
è un semplice valore definito nella libreria standard. Se non sono stati definiti nella libreria standard che si potrebbe definire da soli (scrivendo myUndefined = error "My Undefined
per esempio).
In Java null
è una parola chiave. Se non ci fosse parola chiave null
, non sarebbe in grado di definirlo (facendo l'equivalente della definizione Haskell, vale a dire Object myNull = throw(new Exception())
, non funzionerebbe, perché l'espressione sarebbe stata valutata proprio lì).