Entendiendo el Bool de Haskell Derivando un Ord
boolean (3)
Learn You a Haskell presenta el tipo Bool
:
data Bool = False | True deriving (Ord)
No entiendo la razón para comparar los de Bool
.
> False `compare` True
LT
> True `compare` False
GT
¿Qué se perdería si Bool
no se derivara de Ord
?
¡Es porque los diseñadores de Haskell cometieron un error! Nunca vi un libro de texto de matemáticas que mencionara el ordenamiento de los booleanos. Sólo porque pueden ser, no significa con debería. Algunos de nosotros usamos Haskell exactamente porque no nos permite / nos protege de cosas confusas / sin sentido en muchos casos, pero no en este.
instance Ord Bool
hace que a => b
signifique lo que usted espera que a <= b
signifique.
Argumentos anteriores a favor de la instance Ord Bool
donde se pueden hacer más tipos comparables implícitamente. Continuando con esa línea de argumentación, algunos podrían querer hacer que todos los tipos sean comparables e incluso tener una tipificación dinámica débil y omitir las clases de tipos por completo. Pero queremos escribir con fuerza exactamente para no permitir lo que obviamente no es correcto, y la instance Ord Bool
derrota ese propósito.
En cuanto al argumento de que Bool es un entramado acotado. A diferencia de boolean: = {True, False}, lo que tenemos en Haskell es Bool: = {True, False, bottom} ya no es un enrejado acotado, ya que True y False son elementos de identidad en la presunción de bottom. Eso está relacionado con los comentarios que discuten && vs min, etc.
La instancia de Ord
para Bool
vuelve mucho más importante cuando necesita comparar valores que contengan Bool
algún lugar dentro. Por ejemplo, sin él no podríamos escribir expresiones como:
[False,True] `compare` [False,True,False]
(3, False) < (3, True)
data Person = Person { name :: String, member :: Bool } deriving (Eq, Ord)
etc.
Bool
forma un enrejado acotado * donde False
es inferior y True
es superior . Esta red limitada define un orden (total) donde False
realmente es estrictamente menor que True
. (También son los únicos elementos de esta red.)
Las operaciones booleanas and
y or
también pueden considerarse como reunirse y unirse , respectivamente, en esta red. Meet encuentra el mayor límite inferior y join encuentra el menor límite superior. Esto significa que a && False = False
es lo mismo que decir que el límite inferior del fondo y cualquier otra cosa es inferior, y a || True = True
a || True = True
es lo mismo que decir que el límite superior de arriba y cualquier cosa es superior. Así que cumplir y unirse, que utilizan la propiedad de pedido de los booleanos, son equivalentes a las operaciones booleanas con las que está familiarizado.
Puedes usar min
y max
para mostrar esto en Haskell:
False `min` True = False -- this is the greatest lower bound
False && True = False -- so is this
False `max` True = True -- this is the least upper bound
False || True = True -- so is this
Esto demuestra que puedes definir &&
y ||
solo de la instancia de Ord
derivada:
(&&) = min
(||) = max
Tenga en cuenta que estas definiciones no son equivalentes en presencia de un tipo diferente de fondo porque (&&)
y (||)
son cortocircuitos (no estrictos en el segundo argumento cuando el primero es False
o True
, respectivamente), mientras que min
y max
no son
También, una pequeña corrección: La cláusula deriving
no dice que Bool
"deriva de" Ord
. Le indica a GHC que derive una instancia de la clase de tipos Ord
para el tipo Bool
.
* Más concretamente, una celosía distributiva complementada . Más específicamente aún, un álgebra booleana .