tipo - ¿Cuál es la diferencia entre undefined en Haskell y null en Java?
null nan undefined javascript (2)
Ambos son términos cuyo tipo es la intersección de todos los tipos (deshabitado). Ambos pueden pasarse en el código sin fallar hasta que uno intente evaluarlos. La única diferencia que puedo ver es que en Java, hay una laguna que permite evaluar null
para exactamente una operación, que es la comparación de igualdad de referencia ( ==
) - mientras que en Haskell undefined
no se puede evaluar en absoluto sin tirar una excepción. ¿Es esta la única diferencia?
Editar
Lo que estoy tratando de hacer con esta pregunta es, ¿por qué fue null
incluir en Java una decisión aparentemente tan mala, y cómo se escapa Haskell? Me parece que el verdadero problema es que puede hacer algo útil con null
, es decir, puede verificar la nulidad . Debido a que se le permite hacer esto, se ha convertido en una convención estándar pasar valores nulos en el código y hacer que indiquen "sin resultado" en lugar de "hay un error lógico en este programa". Mientras que en Haskell, no hay forma de verificar si un término se evalúa al final sin evaluarlo y sin que el programa explote, por lo que nunca podría usarse de tal forma que indique "sin resultado". En cambio, uno se ve obligado a usar algo como Maybe
.
Lo siento si parece que estoy jugando rápido con el término "evaluar" ... Estoy tratando de hacer una analogía aquí y tengo problemas para redactarla con precisión. Supongo que eso es una señal de que la analogía es imprecisa.
¿Cuál es la diferencia entre undefined en Haskell y null en Java?
Ok, retrocedamos un poco.
"indefinido" en Haskell es un ejemplo de un valor "inferior" (denotado ⊥). Tal valor representa cualquier estado indefinido, atascado o parcial en el programa.
Existen muchas formas diferentes de fondo: bucles sin terminación, excepciones, fallas de coincidencia de patrones, básicamente cualquier estado en el programa que no está definido en algún sentido. El valor undefined :: a
es un ejemplo canónico de un valor que coloca el programa en un estado indefinido.
undefined
sí mismo no es particularmente especial, no está conectado, y puedes implementar Haskell''s undefined
usando cualquier expresión de rendimiento inferior. Por ejemplo, esta es una implementación válida de undefined
:
> undefined = undefined
O saliendo inmediatamente (el antiguo compilador de Gofer usó esta definición):
> undefined | False = undefined
La propiedad principal de fondo es que si una expresión se evalúa en la parte inferior, todo su programa se evaluará hasta abajo: el programa está en un estado indefinido.
¿Por qué querrías tal valor? Bueno, en un lenguaje perezoso, a menudo puede manipular estructuras o funciones que almacenan valores mínimos, sin que el programa sea en sí mismo inferior.
Por ejemplo, una lista de bucles infinitos es perfectamente cromática:
> let xs = [ let f = f in f
, let g n = g (n+1) in g 0
]
> :t xs
xs :: [t]
> length xs
2
Simplemente no puedo hacer mucho con los elementos de la lista:
> head xs
^CInterrupted.
Esta manipulación de infinitas cosas es parte de por qué Haskell es tan divertido y expresivo. Como resultado de la pereza, Haskell presta especial atención a los valores mínimos.
Sin embargo, claramente, el concepto de fondo se aplica igualmente bien a Java o a cualquier lenguaje (no total). En Java, hay muchas expresiones que arrojan valores "inferiores":
- comparando una referencia contra nulo (aunque nota, no
null
sí mismo, que está bien definido); - división por cero;
- excepciones fuera de límites;
- un bucle infinito, etc.
Simplemente no tiene la capacidad de sustituir un fondo por otro muy fácilmente, y el compilador de Java no hace mucho para razonar sobre los valores inferiores. Sin embargo, tales valores están ahí.
En resumen,
- desreferenciar un valor
null
en Java es una expresión específica que arroja un valor inferior en Java; - el valor
undefined
en Haskell es una expresión genérica de rendimiento inferior que se puede utilizar en cualquier lugar donde se requiera un valor inferior en Haskell.
Así es como son similares.
Posdata
En cuanto a la pregunta de null
sí: ¿por qué se considera mala forma?
- En primer lugar, el
null
de Java es esencialmente equivalente a agregar unMaybe a
implícito a cada tipoa
en Haskell . - Desreferencia
null
es equivalente a la coincidencia de patrones solo para el casoJust
:f (Just a) = ... a ...
Entonces, cuando el valor pasado es Nothing
(en Haskell), o null
(en Java), su programa alcanza un estado indefinido. Esto es malo: tu programa falla.
Por lo tanto, al agregar valores null
a todos los tipos, hace que sea mucho más fácil crear valores mínimos por accidente; los tipos ya no lo ayudan. Tu lenguaje ya no te ayuda a prevenir ese tipo de error en particular, y eso es malo.
Por supuesto, otros valores de fondo todavía están allí: excepciones (como undefined
) o bucles infinitos. Agregar un nuevo modo de falla posible a cada función - desreferenciando null
- solo hace que sea más fácil escribir programas que fallan.
Tu descripción no es del todo correcta. Estás diciendo que null
no puede ser evaluado. Sin embargo, dado que java es un lenguaje entusiasta, esto significaría que f(null)
lanzaría un NPE sin importar la definición de f
(porque los argumentos del método siempre se evalúan antes de que el método se ejecute).
La única razón por la que puedes pasar undefined
en haskell sin obtener una excepción es que haskell es flojo y no evalúa los argumentos a menos que sea necesario.
Otra diferencia entre indefinido y nulo es que undefined
es un valor simple definido en la biblioteca estándar. Si no estuviera definido en la biblioteca estándar, podría definirlo usted mismo (escribiendo myUndefined = error "My Undefined
por ejemplo).
En Java null
es una palabra clave. Si no hubiera una palabra clave null
, no sería capaz de definirla (haciendo el equivalente de la definición de Object myNull = throw(new Exception())
, es decir, el Object myNull = throw(new Exception())
no funcionaría porque la expresión se evaluaría allí mismo) .