2010-07-29 14 views
6

read se define en el preludio comoHaskell: leído y tipo firmas

read :: (Read a) => String -> a 

y pueden ser utilizados como por ejemplo, read "1" :: Int.

ahora una función

readOne :: (Read a) => [String] -> (a, [String]) 
readOne (x:xs) = (read x,xs) 

utilizado con readOne ["1","foo"] resultados (como se esperaba) en el error

Ambiguous type variable 'a' in the constraint:
'Read a' arising from a use of 'readOne' at :1:0-18
Probable fix: add a type signature that fixes these type variable(s)

Pero readOne ["1","foo"] :: Int no funciona, mientras que

readOneInt :: [String] -> (Int, [String]) 
readOneInt = readOne 

obras muy bien:

> readOneInt ["1", "foo"] 
(1,["foo"]) 

Así que: ¿cómo puedo agregar una firma de tipo de readOne sin definir una nueva función como readOneInt?

Respuesta

9

readOne ["1","foo"] :: Int no funciona porque readOne no podría devolver un Int, siempre devuelve una tupla, cuyo segundo elemento es un [String]. readOne ["1", "foo"] :: (Int, [String]) funcionará.

Tenga en cuenta que solo necesita especificar el tipo si no se puede inferir. Si usa el resultado de readOne en un contexto donde necesita ser un Int, puede usar readOne sin anotaciones de tipo. Ejemplo:

let inc (i, strs) = (i + 1, strs) in 
inc (readOne ["1", "foo"]) 
-- (2, ["foo"]) 
+0

¡Muchas gracias! –

+2

¡Cuidado! El ejemplo al final solo funcionará en ghci porque el tipo de 1 está predeterminado en 'Entero '. Si le preguntas a ghci por el tipo de expresión (a través de ': t'), obtienes' (Num a, Read a) => (a, [String]) 'que tiene el mismo problema que antes. 'asTypeOf' puede ayudar aquí, como en' asTypeOf (readOne ["1", "foo"]) (0 :: Double, [] :: [String]) '- que normalmente escribiría con asTypeOf en backticks pero SO no le gusta los backticks doblemente escapados. – yatima2975