此代码无法在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)
$
我刚输入“你好!”然后输入。请注意,我在OS X上运行x86_64 GHC,这被认为是不稳定的。
EDIT2 :我将readLn更改为getLine,它无缘无故地神奇地工作。我想知道为什么,但我很高兴它有效。
最终代码:
import System.IO
main = do
z <- getLine
print z
答案 0 :(得分:27)
readLn作为类型:Read a => IO a
。它从用户读取一行,然后将该字符串解析为类型a
。什么是a
类型?这是你想要的任何东西(只要它是Read
的一个实例)。例如:
readAInt :: IO Int
readAInt = readLn
readABool :: IO Bool
readABool = readLn
print
的类型为Show a => a -> IO ()
。它采用的类型是Show
的实例,并将其打印出来。例如,要打印True
,您可以使用print True
。要打印Int 42,您可以使用print 42
。
在您的示例中,您一起使用print和readLn。这不起作用,因为haskell无法确定应返回的类型readLn
。 print
可以采用任何可显示的类型,因此它不会限制返回哪种类型。这使得readLn
的返回类型不明确,因为haskell无法弄清楚类型。这是错误消息所说的内容。
您可能只需要存储用户输入的字符串,而不是将其读入您自己的类型。您可以使用类型为getLine :: IO String
的getLine执行此操作。类似地,您可以使用putStrLn
而不是print
来打印字符串。 putStrLn
的类型为String -> IO ()
。
答案 1 :(得分:16)
这是您将代码更改为的内容,对吧?
import System.IO
main = do
z <- readLn
putStrLn z
putStrLn
将String
写入stdout,因此z
为String
。因此readLn
将从stdin中读取String
。
但是...... readLn
期望从stdin读取Haskell格式的值。即,不要期望你键入类似This is a string
的东西,而是用引号来预测它:"This is a string"
。
要修复,请将readLn
替换为getLine
,其中读取文字文本,而不是Haskell格式的字符串。
import System.IO
main = do
z <- getLine
putStrLn z
答案 2 :(得分:10)
readLn读回您指定的类型,因此不能以这种方式使用:它需要在指定其类型的函数中使用。另一方面,getLine总是返回一个String,所以它可以做你想要的。
值得注意的是,您可能还想使用putStrLn而不是print; print会添加引号。
因此,GHCi中的do { z <- getLine; putStrLn z; }
应该做你想做的事。