2012-03-04 30 views
5

estoy usando esta aplicación de maybeRead:Haskell: leer un número (entero o punto flotante)

maybeRead :: (Read a) => String -> Maybe a 
maybeRead = fmap fst . listToMaybe . filter (null . dropWhile isSpace . snd) . reads 

y mi propia función getNum que impulsa hasta que se pone de entrada válida:

getNum :: (Num a, Read a) => String -> IO a 
getNum s = do 
    putStr s 
    input <- fmap maybeRead getLine 
    if isNothing input 
     then getNum s 
     else return $ fromJust input 

Sin embargo si ingreso 5.2, lo trata como una entrada incorrecta: ¿por qué? No hay ocurrencias de Int y Integer en mi código. Solo estoy usando Num, ya que quiero aceptar cualquier tipo de número.

Si lo llamo explícitamente como getNum "Enter a number: " :: IO Double, entonces funciona. ¿Tengo que hacer esto? ¿El sistema de tipos de Haskell me está engañando para que piense que debería ser capaz de hacer esto cuando en realidad es imposible sin una escritura dinámica completa? Si es así, ¿por qué mi código incluso compila? ¿Por qué asume enteros?

+2

Nota estilística pequeña: es mejor utilizar la coincidencia de patrones que 'isNothing' y' fromJust', por lo que la expresión 'if' puede reemplazarse con' case input of Nothing -> getNum s; Solo x -> devolver x'. – hammar

+0

Gracias, eso se ve mucho mejor. – mk12

Respuesta

13

Su función aceptará efectivamente Integer, Float, o cualquier otra instancia de Num. Sin embargo, qué tipo acepta y, por extensión, cómo analiza el String, no está determinado por la entrada que recibe, está determinado por de qué tipo debe ser el resultado en función de lo que haga con él.

Supongamos que usa getNum y pasa el valor resultante a algo que necesita un Float; en ese caso, analizará un valor de Float. Si lo pasa a algo que necesita un Integer, lo analizará.

En cuanto a lo que se supone Integer, hay un sistema de "morosos" para este tipo de specified in the Haskell Report ambiguas, y las reglas dicen que un tipo ambigua con una restricción Num debe predeterminado a Integer.

+0

Bien, entonces supongo que en mi ejemplo tendría que agregar ':: (Fractional a, Read a) => IO a' cuando llamo a' getNum' para permitir números fraccionarios (y no quiero especificar explícitamente flotante o doble). – mk12

+1

Sí, pero tenga en cuenta que al agregar una restricción 'Fraccionaria' se limitará a aceptar * solo * instancias de' Fraccionarial', por lo que no podría usarlo para otros tipos de esa manera. La mayoría de las veces en un programa real conocerá un tipo específico que necesita, por lo que generalmente no hay ninguna razón para restringir las cosas, a excepción de cosas como las pruebas en GHCi. –

+1

No lo agregué a la función real, lo agregué como una anotación de tipo cuando uso la función. No estoy muy seguro de entender lo que dices en la última oración: ¿no hay restricciones de clase de tipo omnipresentes en el código de Haskell para generalizar funciones? – mk12

Cuestiones relacionadas