digamos que tengo el siguiente códigoHaskell: Seguridad de tipos con diferentes valores booleanos lógicamente
type IsTall = Bool
type IsAlive = Bool
is_short_alive_person is_tall is_alive = (not is_tall) && is_alive
Say, más adelante, tengo el siguiente
a :: IsAlive
a = False
b :: IsTall
b = True
y llame a la siguiente , consiguiendo los dos argumentos en torno a la manera equivocada:
is_short_alive_person a b
Esto compila con éxito por desgracia, y al tiempo de ejecución de la gente alta muertos en su lugar se encuentran en lugar de personas cortas y vivas.
Me gustaría que no se compile el ejemplo anterior.
Mi primer intento fue:
newtype IsAlive = IsAlive Bool
newtype IsTall = IsTall Bool
Pero entonces no puede hacer algo así.
switch_height :: IsTall -> IsTall
switch_height h = not h
Como not
no está definido en IsTall
s, sólo Bool
s.
Podría extraer explícitamente el Bool
s todo el tiempo, pero eso en gran medida frustra el propósito.
Básicamente, quiero IsTall
s interactuar con otros IsTall
s, al igual que lo son Bool
s, excepto que no van a interactuar con Bool
s y s IsAlive
sin una conversión explícita.
¿Cuál es la mejor manera de lograr esto.
p.s. Creo que he logrado esto con los números haciendo en GHC:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype UserID = UserID Int deriving (Eq, Ord, Num)
newtype GroupID = GroupID Int deriving (Eq, Ord, Num)
(es decir, ID de usuario y de GroupID de no deberían interactuar)
pero me parece que no puede hacer esto con Bool
s (que deriva de Bool no funciona). Ni siquiera estoy seguro de que lo anterior sea el mejor enfoque de todos modos.
Los tipos deseados 'IsTall' y' IsAlive' son una idea terrible. Es una falsa generalización de la idea generalmente decente de usar tipos disjuntos para garantizar la seguridad del tipo. Compare esto con su 'UserID' y' GroupID'; en ese caso, tiene sentido tener tipos separados porque no tiene sentido pasar un 'UserId' donde se necesita un' GroupID', o agregar uno al otro (aunque probablemente ninguno debe implementar 'Num'). Sin embargo, tiene sentido probar si una persona es alta * y * viva, alta * o * viva, * no * alta * y * viva, etc. –
sacundim: En gran medida cambié de opinión hasta este punto de ver. Terminé usando cosas como 'newtype Height = Tall | Corto' y luego haciendo 'x == Tall', etc. Un poco más de tipeo, pero pensé que hacía que el código fuera más legible y seguro. – Clinton