Me gustaría leer algunos datos que a su vez especifican el tipo de datos a usar.Lectura y representación de entrada que especifica el tipo de datos a usar
Por ejemplo, vamos a suponer que puede haber entradas del usuario como éstas:
integer pair 1 2
integer triple 1 2 3
real pair 1 2
real triple 1 2 3
y hay un tipo de datos para representarla:
data (MValue a) => T a = TP (Pair a) | TT (Triple a)
deriving (Show, Eq)
data Pair a = Pair a a deriving (Show, Eq)
data Triple a = Triple a a a deriving (Show, Eq)
donde los tipos de valores permitidos tienen que pertenecer a MValue
clase:
class (Num a, Read a) => MValue a where
typename :: a -> String
readval :: [String] -> Maybe a
instance MValue Int where
typename _ = "integer"
readval [s] = maybeRead s
readval _ = Nothing
instance MValue Double where
typename _ = "real"
readval [s] = maybeRead s
readval _ = Nothing
maybeRead s =
case reads s of
[(x,_)] -> Just x
_ -> Nothing
me puede escribir fácilmente los lectores para Pair
s y Triple
s:
readPair (w1:w2:[]) = Pair <$> maybeRead w1 <*> maybeRead w2
readTriple (w1:w2:w3:[]) = Triple <$> maybeRead w1 <*> maybeRead w2 <*> maybeRead w3
El problema es ¿Cómo se escribe un lector polimórfica para toda la T a
tipo:?
que quiero:
- El tipo
a
es elegido por la persona que llama. readT
debe producirNothing
si la entrada del usuario es incompatible cona
.readT
debe producirJust (T a)
si la entrada es válida.- Los números se deben leer como enteros o como dobles según la entrada.
Una implementación ingenua
readT :: (MValue a, Read a) => String -> Maybe (T a)
readT s =
case words s of
(tp:frm:rest) ->
if tp /= typename (undefined :: a)
then Nothing
else case frm of
"pair" -> TP <$> readPair rest
"triple" -> TT <$> readTriple rest
_ -> Nothing
_ -> Nothing
da un error en la línea if tp /= typename (undefined :: a)
:
rd.hs:45:17:
Ambiguous type variable `a' in the constraint:
`MValue a' arising from a use of `typename' at rd.hs:45:17-41
Probable fix: add a type signature that fixes these type variable(s)
Failed, modules loaded: none.
El error desaparece si quito esta comprobación, pero ¿cómo puedo comprobar si la entrada de usuario es compatible con el tipo de datos elegido por la persona que llama? Una solución podría ser tener readTInt
y readTDouble
separados, pero me gustaría que el mismo readT
funcione polimórficamente de la misma manera que read
.
Gracias. Esto funciona. El truco con 'resultado' como argumento para indefinido' Maybe (T a) -> a' es inesperado. – sastanin
En realidad, 'result' y' undefined' son argumentos para 'const :: a -> Maybe (T a) -> a', lo que obliga a que sus tipos se relacionen de la forma indicada por la firma de tipo explícita en' const '. Pero sí, '(indefinido :: Maybe (T a) -> a) result' también funcionaría. – mokus