Lea de stdin en Haskell usando IO.readLn
ghc (3)
Esto es a lo que le cambiaste el código, ¿verdad?
import System.IO
main = do
z <- readLn
putStrLn z
putStrLn
escribe una String
en stdout, por lo que z
es una String
. Por readLn
tanto, readLn
leerá una String
de stdin.
PERO ... readLn
espera leer un valor con formato Haskell de stdin. es decir, en lugar de esperar que escriba algo como This is a string
, lo anticipa entre comillas: "This is a string"
.
Para solucionarlo, reemplace readLn
con getLine
, que se lee en texto literal, no en una cadena con formato Haskell.
import System.IO
main = do
z <- getLine
putStrLn z
Este código no se compila en GHC 7.0.3:
import System.IO
main = do
z <- readLn
print z
Mi intención es leer una línea de stdin y almacenarla en z, para hacer cosas más avanzadas con ella más adelante. El mensaje de error se ve así:
test.hs:5:9:
Ambiguous type variable `a0'' in the constraints:
(Show a0) arising from a use of `print'' at test.hs:5:9-13
(Read a0) arising from a use of `readLn'' at test.hs:4:14-19
Probable fix: add a type signature that fixes these type variable(s)
In a stmt of a ''do'' expression: print z
In the expression:
do { z <- readLn;
print z;
return () }
In an equation for `main'':
main
= do { z <- readLn;
print z;
return () }
Obviamente, hay algo fundamental que aún no entendí; por favor, explícame por qué no funciona y cómo solucionarlo.
EDIT1 : arreglé el error de compilación al cambiar print z
por putStrLn z
, por lo que GHC entiende que quiero leer una cadena. Pero cuando ejecuto el programa, obtengo un error de tiempo de ejecución que no puedo entender:
$ ./test
hello!
test: user error (Prelude.readIO: no parse)
$
Acabo de escribir "hola!" y luego entrar Tenga en cuenta que estoy ejecutando x86_64 GHC en OS X, que se considera inestable.
EDIT2 : Cambié readLn a getLine y mágicamente funciona sin ninguna razón. Me gustaría saber por qué, pero estoy feliz de que funcione.
Código final:
import System.IO
main = do
z <- getLine
print z
readLn como tipo: Read a => IO a
. Lee una línea del usuario y luego analiza la cadena en el tipo a
. ¿Qué es tipo a
? Es lo que quieras (siempre que sea una instancia de Read
). Por ejemplo:
readAInt :: IO Int
readAInt = readLn
readABool :: IO Bool
readABool = readLn
print
tiene el tipo Show a => a -> IO ()
. Toma un tipo que es una instancia de Show
, y lo imprime. Por ejemplo, para imprimir True
, puede usar print True
. Para imprimir el Int 42, puede usar print 42
.
En su ejemplo, está usando print y readLn juntos. Esto no funciona, ya que haskell no puede descifrar qué tipo debe devolver readLn
. print
puede tomar cualquier tipo que se pueda mostrar, por lo que no se restringe a uno qué tipo se devolverá. Esto hace que el tipo de retorno de readLn
ambiguo, ya que readLn
no puede determinar el tipo. Esto es lo que está diciendo el mensaje de error.
Lo que probablemente es qué almacenar solo la cadena que ingresa el usuario, en lugar de leerla en su propio tipo. Puede hacerlo con getLine, que tiene el tipo getLine :: IO String
. De manera similar, puede usar putStrLn
lugar de print
para simplemente imprimir una Cadena. putStrLn
tiene el tipo String -> IO ()
.
readLn lee un tipo que especifique y, por lo tanto, no se puede usar de esta manera: debe usarse en una función que especifique su tipo. getLine, por otro lado, siempre devuelve un String, por lo que hace lo que quiere.
Vale la pena señalar que es posible que desee utilizar putStrLn en lugar de imprimir también; imprimir agregará comillas.
Por do { z <- getLine; putStrLn z; }
tanto, do { z <- getLine; putStrLn z; }
do { z <- getLine; putStrLn z; }
do { z <- getLine; putStrLn z; }
en GHCi debería hacer lo que quieras.