IO Char和[Char]之间的匹配类型错误

rns*_*nso 1 haskell types

我正在尝试从用户那里获取输入并根据输入(从此处修改的代码)进行打印:

import Data.Char (toUpper)

isGreen = do
    putStrLn "Is green your favorite color?"
    inpStr <- getLine
    if (toUpper (head inpStr) == 'Y') then "YES" else "NO"
    -- following also does not work: 
    -- if (toUpper (head inpStr) == 'Y') then return "YES" else return "NO" 

main = do
    print isGreen
Run Code Online (Sandbox Code Playgroud)

但是,我遇到很多错误:

testing.hs:7:44: error:
    • Couldn't match type ‘[]’ with ‘IO’
      Expected type: IO Char
        Actual type: [Char]
    • In the expression: "YES"
      In a stmt of a 'do' block:
        if (toUpper (head inpStr) == 'Y') then "YES" else "NO"
      In the expression:
        do { putStrLn "Is green your favorite color?";
             inpStr <- getLine;
             if (toUpper (head inpStr) == 'Y') then "YES" else "NO" }

testing.hs:7:55: error:
    • Couldn't match type ‘[]’ with ‘IO’
      Expected type: IO Char
        Actual type: [Char]
    • In the expression: "NO"
      In a stmt of a 'do' block:
        if (toUpper (head inpStr) == 'Y') then "YES" else "NO"
      In the expression:
        do { putStrLn "Is green your favorite color?";
             inpStr <- getLine;
             if (toUpper (head inpStr) == 'Y') then "YES" else "NO" }

testing.hs:12:5: error:
    • No instance for (Show (IO Char)) arising from a use of ‘print’
    • In a stmt of a 'do' block: print isGreen
      In the expression: do { print isGreen }
      In an equation for ‘main’: main = do { print isGreen }
Run Code Online (Sandbox Code Playgroud)

问题在哪里,如何解决?

Rob*_*ond 8

本质上,您的问题是使IO代码与非IO或“纯”代码混淆。

在中isGreen,您有一个do涉及putStrLn和的块getLine。这意味着函数必须返回某种类型的值IO a。您无法从中获得“纯字符串”,这似乎是您的意图。do块的最后一行必须是单声道值,在这种情况下为IO值-因此您不能在这里简单地输入字符串。

但是,您可以使用return函数从中制作IO String出a String,如注释掉的代码“也不起作用”所示:

if (toUpper (head inpStr) == 'Y') then return "YES" else return "NO" 
Run Code Online (Sandbox Code Playgroud)

就工作而言,这很好,并且是必需的isGreen。发生错误是由于中发生了什么main。您不能有print一个IOIO String-an实际上不是字符串,它基本上是将来字符串的“承诺”,它将仅在运行时基于(在这种情况下)用户输入来实现。

但这毕竟main是一个IO动作,所以这不是问题。只需这样做:

main = do
    isItGreen <- isGreen
    print isItGreen
Run Code Online (Sandbox Code Playgroud)

或者,完全相同,但更简洁

main = isGreen >>= print
Run Code Online (Sandbox Code Playgroud)

您可能更愿意putStrLn使用print,它在打印字符串时将包含引号。

请注意,如果您为每个顶级值(此处isGreenmain)都包括了一个类型签名,那么您将从编译器中获得有关错误位置的更多有用信息。


che*_*ner 5

isGreen使用IO,因此类型必须是IO String,而不是String。这是一个IO操作,可以产生一个字符串,而不是字符串本身。

isGreen :: IO String
isGreen = do
    putStrLn "Is green your favorite color?"
    inpStr <- getLine
    return $ if (toUpper (head inpStr) == 'Y') then "YES" else "NO"
Run Code Online (Sandbox Code Playgroud)

同样,print期望使用String,而不是IO String,因此您需要使用IOmonad实例。(实际上,你应该使用putStrLn,因为你不需要隐含的showprint将使用。)

main = isGreen >>= putStrLn
Run Code Online (Sandbox Code Playgroud)

在这里,>>=正在创建一个 IO动作,该IO动作将在左侧(isGreen)执行该动作,并将产生的值传递给右侧(putStrLn)的函数。

  • Haskell只允许纯函数,所以`getLine`不能是一个函数。相反,它是一个称为IO操作的“值”。每次执行该动作时,它都可以产生一个新值,但是Haskell程序员*您*无法执行该值。只有运行时才能执行IO操作,因此,您最多只能执行* compose * IO操作来生成最终要执行的操作。 (2认同)