Se puede utilizar un tipo de datos abstracto con un smart constructor:
newtype Digit = Digit { digitVal :: Int }
deriving (Eq, Ord, Show)
mkDigit :: Int -> Maybe Digit
mkDigit n
| n >= 0 && n < 10 = Just (Digit n)
| otherwise = Nothing
Si pones esto en otro módulo y no exporta el constructor Digit
, a continuación, el código de cliente no puede construir valores del tipo Digit
fuera del rango [0,9], pero tiene que envolverlo y desenvolverlo manualmente para usarlo. Podría definir una instancia Num
que haga aritmética modular, si eso fuera útil; eso también te permitiría usar literales numéricos para construir Dígitos. (Del mismo modo para Enum
y Bounded
.)
Sin embargo, esto no garantiza que nunca intenta crear un dígito inválido, sólo que nunca se hace . Si desea más seguridad, entonces la solución manual que ofrece Jan es mejor, a costa de ser menos conveniente. (Y si define una instancia Num
para ese tipo de dígito, terminará igual de "inseguro", porque podría escribir 42 :: Digit
gracias al soporte numérico literal que obtendría)
(Si usted no sabe lo que newtype
es decir, que es básicamente data
de tipos de datos con un solo campo, el estricto;. un envoltorio newtype alrededor T tendrá la misma representación en tiempo de ejecución como T es básicamente una optimización, por lo que puede pretender que dice data
con el fin de entender esto.)
Editar: Para la solución más orientada a la teoría, 100%, consulte la sección de comentarios algo apretados de esta respuesta.
Eso haría el trabajo, pero el sistema de tipos no es el que está manejando el problema. Eso es más de lo que estoy buscando. –
Derecha: la garantía adicional aquí es que ningún valor de tipo 'Digit' puede ser inválido, en lugar de simplemente validar un' Expr' después de los hechos. Tenga en cuenta que incluso la solución de enumeración manual permite valores como 'error 'oops' ':: Digit'. Hay formas de manejar estas cosas de manera sólida y conveniente en sistemas de tipo avanzado, pero todavía no han llegado a Haskell, por lo que un compromiso como este es probablemente la mejor solución. (No es que hayan llegado a ningún otro lenguaje del "mundo real".) – ehird
Si el sistema de tipos estuviera manejando el problema, no tendría que validar el 'Expr' porque no se compilaría en el primer lugar, ¿verdad? –