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

时间:2019-09-17 14:42:57

标签: haskell types

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

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

但是,我遇到很多错误:

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 }

问题出在哪里,如何解决?

3 个答案:

答案 0 :(得分:8)

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

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

但是,您可以使用return函数从IO String中生成String,就像注释掉的代码“也不起作用”一样:

if (toUpper (head inpStr) == 'Y') then return "YES" else return "NO" 

isGreen而言,这很好,并且是必需的。由于main中发生的错误而导致错误。您不能print的{​​{1}}值-IO实际上不是字符串,它基本上是将来字符串的“承诺”,仅会在运行时基于(在这种情况下) )用户的输入。

但是由于IO String仍然是main的动作,所以这不是问题。只需这样做:

IO

或完全等价,但imo更简洁,

main = do
    isItGreen <- isGreen
    print isItGreen

您可能更喜欢main = isGreen >>= print 而不是putStrLn,它在打印字符串时将包含引号。

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

答案 1 :(得分: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"

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

main = isGreen >>= putStrLn

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

答案 2 :(得分:2)

由于app = QtWidgets.QApplication(sys.argv) window = Window() window.viewer.printfromwindow() isGreen,因此您不能使用IO a作为最后一行。您需要返回一个if … then … else …

不过,您可以在此处使用IO a(或pure,尽管它本质上没有错,):

return

这里import Data.Char(toUpper) isGreen :: IO String isGreen = do putStrLn "Is green your favorite color?" inpStr <- getLine pure (if "Y" == take 1 (map toUpper inpStr) then "YES" else "NO")更安全,因为如果用户写了一个空行,那么"Y" == take 1 (map toUpper inpStr)将在空列表上出错。

由于head的类型为isGreen,因此您不能使用IO String,因此可以在这里使用 bind print isGreen

(>>=)
相关问题