3

我对 Haskell 比较陌生,我目前正在使用 LearnYouAHaskell。我正在尝试获取一个由空格分隔的字符串,并将其分解为一个较小的字符串列表。我目前的程序:

main = do 
    putStrLn "Insert a string to convert: "
    -- Input string
    line <- getLine
    words line;

但在这种情况下,它告诉我我遇到了 IO 错误。据我了解,getLine 是一个动作,所以由于这是不纯的,我必须将它绑定到“line”。Line 是 getLine 的准确表示,它是一个 IO String。

但是, line 不应该是字符串吗?当我尝试在线使用单词时,它告诉我“无法将预期类型“IO a0”与实际类型 [String] 匹配

好像 line 不是字符串。此外,我可以在程序本身中使用 :t 行来查看它是否是正确的类型吗?

我为新手问题道歉,但我有点卡住了。

编辑:

我在 GHCI 中做了类似的事情,它告诉我我的类型实际上是一个普通的字符串。我不明白。

Prelude> line <- getLine
"Hello fellows"
Prelude> :t line
line :: String
Prelude> words line
["Hello","fellows"]

为什么那行不通?

4

2 回答 2

7

在haskell中如果你想返回一个值,你必须这样说:

main = do 
    putStrLn "Insert a string to convert: "
    -- Input string
    line <- getLine
    return (words line)

words line不是 IO 操作,它是字符串列表,因此不能是do块中的语句。

return :: Monad m => a -> m a在这种情况下,我们可以将其专门化为 type a -> IO a,然后专门化为[String] -> IO [String]. 块中的每个语句都do必须是IO语句。


更进一步:

如果你想编译你的程序,你应该有main :: IO(),这意味着你不应该返回你的列表。

例如,如果您想将process这些字符串转换为单个字符串然后输出,您可以这样做

process :: [String] -> String
process xss = "I don't know, some answer"

main = do 
    putStrLn "Insert a string to convert: "
    -- Input string
    line <- getLine
    putStrLn (process (words line))

尽管我个人会将最后一行写为putStrLn $ process.words $ line.


您在 GHCi 中的互动

Prelude> line <- getLine
"Hello fellows"
Prelude> :t line
line :: String
Prelude> words line
["Hello","fellows"]

正在使用 GHCi 实际上不仅仅是在 IO monad 中运行的事实。在 GHCi 中,如果您的输入是do块中的有效行,它将运行,但如果它是纯代码,它将被评估和打印。(像这样的交互式解释器通常称为 Read-Eval-Print-Loop 的 REPL。)

于 2013-02-05T22:23:05.163 回答
3

好吧,问题是你想做什么words line

words linedo 块中作为一行什么都不做,但要让它工作,你必须使用return它来将它包装在 IO monad 中:

main = do 
    putStrLn "Insert a string to convert: "
    -- Input string
    line <- getLine
    return (words line);

无论如何,也许您想打印它?

main = do 
    putStrLn "Insert a string to convert: "
    -- Input string
    line <- getLine
    print (words line);
于 2013-02-05T22:23:55.037 回答