使用 IO.readLn 从 Haskell 中的 stdin 读取单行
此代码无法在 GHC 7.0.3 中编译:
import System.IO
main = do
z <- readLn
print z
我的目的是从 stdin 读取一行并将其存储在 z 中,以便稍后用它做更高级的事情。错误消息看起来像:
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 () }
显然有一些基本的东西我还没有理解;请向我解释为什么它不起作用以及如何修复它。
EDIT1:我通过将 print z
更改为 putStrLn z
修复了编译错误,因此 GHC 知道我想读取字符串。但是当我运行该程序时,我收到一个我无法理解的运行时错误:
$ ./test
hello!
test: user error (Prelude.readIO: no parse)
$
我只是输入了“hello!”然后进入。请注意,我在 OS X 上运行 x86_64 GHC,这被认为是不稳定的。
EDIT2:我将 readLn 更改为 getLine,它毫无理由地神奇地工作了。我想知道为什么,但我很高兴它有效。
最终代码:
import System.IO
main = do
z <- getLine
print z
This code does not compile in GHC 7.0.3:
import System.IO
main = do
z <- readLn
print z
My intention is to read one line from stdin and store it in z, to do more advanced stuff with it later on. Error message looks like:
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 () }
Obviously there is something fundamental I haven't understood yet; please explain to me why it doesn't work and how to fix it.
EDIT1: I fixed the compile error by changing print z
to putStrLn z
, so GHC understands that I want to read a string. But when I run the program, I get a runtime error which I can't understand:
$ ./test
hello!
test: user error (Prelude.readIO: no parse)
$
I just typed "hello!" and then enter. Note that I'm running x86_64 GHC on OS X, which is considered unstable.
EDIT2: I changed readLn to getLine and it magically works for no reason. I would like to know why, but I'm happy it works.
Final code:
import System.IO
main = do
z <- getLine
print z
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
readLn 作为类型:
Read a => IO a
。它从用户处读取一行,然后将字符串解析为a
类型。a
类型是什么?它是您想要的任何内容(只要它是Read
的实例)。例如:print
的类型为Show a =>;一个-> IO()。它采用
Show
实例的类型,并将其打印出来。例如,要打印True
,可以使用print True
。要打印 Int 42,您可以使用print 42
。在您的示例中,您同时使用 print 和 readLn 。这是行不通的,因为 haskell 无法确定 readLn 应该返回什么类型。
print
可以采用任何可显示的类型,因此它不限制返回的类型。这使得 readLn 的返回类型不明确,因为 haskell 无法确定类型。这就是错误消息所说的内容。您可能会只存储用户输入的字符串,而不是将其读入您自己的类型。您可以使用 getLine 来完成此操作,它的类型为
getLine :: IO String
。类似地,您可以使用putStrLn
而不是print
来仅打印字符串。putStrLn
的类型为String -> IO()。
readLn as the type:
Read a => IO a
. It reads a line from the user, and then parses the string into typea
. What is typea
? It is whatever you want (as long as it is an instance ofRead
). For example:print
has the typeShow a => a -> IO ()
. It takes a type that is an instance ofShow
, and prints it out. For example, to printTrue
, you can useprint True
. To print the Int 42, you can useprint 42
.In your example, you are using print and readLn together. This doesn't work, as haskell can't figure out what type
readLn
should return.print
can take any type that is showable, so it doesn't restrict to one what type would be returned. This makes the return type ofreadLn
ambiguous as haskell can't figure out the type. This is what the error message is saying.What you probably what it to store just the string being entered by the user, rather than reading it into your own type. You can do this with getLine, which has the type
getLine :: IO String
. Similarily you can useputStrLn
instead ofprint
to just print a String.putStrLn
has the typeString -> IO ()
.这就是你更改代码的原因,对吗?
putStrLn
将一个String
写入 stdout,因此z
是一个String
。因此,readLn
将从标准输入读取String
。但是... readLn 期望从 stdin 读取 Haskell 格式的值。即,它不会期望您输入类似
This is a string
的内容,而是将其放在引号中:“This is a string”
。要修复此问题,请将
readLn
替换为getLine
,它会读取文字文本,而不是 Haskell 格式的字符串。This is what you changed your code to, right?
putStrLn
writes aString
to stdout, soz
is aString
. ThereforereadLn
will read aString
from stdin.BUT...
readLn
expects to read a Haskell-formatted value from stdin. i.e. instead of expecting you to type something likeThis is a string
, it anticipates it in quote marks:"This is a string"
.To fix, replace
readLn
withgetLine
, which reads in literal text, not a Haskell-formatted string.readLn 读回您指定的类型,因此不能以这种方式使用:它需要在指定其类型的函数中使用。另一方面,getLine 始终返回一个字符串,因此它可以执行您想要的操作。
值得注意的是,您可能还想使用 putStrLn 而不是 print ; print 会加引号。
因此 do { z <- getLine; putStrLn z; GHCi 中的 } 应该做你想做的事。
readLn reads back a type that you specify, and so can't be used in this way: it needs to be used in a function that specifies its type. getLine, on the other hand, always returns a String, so it does what you want.
It's worth noting that you might want to use putStrLn instead of print as well; print will add quotation marks.
Thus
do { z <- getLine; putStrLn z; }
in GHCi should do what you want.