使用IO.readLn从Haskell中的stdin读取

Bet*_*mos 15 io haskell ghc

此代码无法在GHC 7.0.3中编译:

import System.IO

main = do
    z <- readLn
    print z
Run Code Online (Sandbox Code Playgroud)

我的目的是从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 () }
Run Code Online (Sandbox Code Playgroud)

显然有一些我尚未理解的基本内容; 请向我解释为什么它不起作用以及如何解决它.

EDIT1:我通过改变固定的编译错误print zputStrLn z,让GHC明白,我想读的字符串.但是当我运行程序时,我得到一个运行时错误,我无法理解:

$ ./test
hello!
test: user error (Prelude.readIO: no parse)
$
Run Code Online (Sandbox Code Playgroud)

我刚输入"你好!" 然后输入.请注意,我在OS X上运行x86_64 GHC,这被认为是不稳定的.

编辑2:我将readLn更改为getLine,它无缘无故地神奇地工作.我想知道为什么,但我很高兴它有效.

最终代码:

import System.IO

main = do
    z <- getLine
    print z
Run Code Online (Sandbox Code Playgroud)

Dav*_*ani 27

readLn作为类型:Read a => IO a.它从用户读取一行,然后将字符串解析为类型a.什么是类型a?这是你想要的任何东西(只要它是一个实例Read).例如:

readAInt :: IO Int
readAInt = readLn

readABool :: IO Bool
readABool = readLn
Run Code Online (Sandbox Code Playgroud)

print有类型Show a => 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 ().


dav*_*420 17

这就是你改变代码的原因吧?

import System.IO

main = do
    z <- readLn
    putStrLn z
Run Code Online (Sandbox Code Playgroud)

putStrLn写一个String到stdout,所以zString.因此将从标准输入readLn读取String.

但是... readLn期望从stdin读取Haskell格式的值.即不是期望你输入类似的东西This is a string,而是用引号来预测它:"This is a string".

要修复,替换readLngetLine,读取文字文本,而不是Haskell格式的字符串.

import System.IO

main = do
    z <- getLine
    putStrLn z
Run Code Online (Sandbox Code Playgroud)


cge*_*cge 10

readLn读回您指定的类型,因此不能以这种方式使用:它需要在指定其类型的函数中使用.另一方面,getLine总是返回一个String,所以它可以做你想要的.

值得注意的是,您可能还想使用putStrLn而不是print; print会添加引号.

因此do { z <- getLine; putStrLn z; }在GHCi中应该做你想要的.