简体   繁体   English

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

[英]Match type errors between IO Char and [Char]

I am trying to get input from user and print out depending on input (code modified from 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

However, I am getting many errors: 但是,我遇到很多错误:

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 }

Where is the problem and how can it be solved? 问题在哪里,如何解决?

Your problem is, essentially, confusing IO code with non-IO, or "pure" code. 本质上,您的问题是将IO代码与非IO代码或“纯”代码混淆。

In isGreen , you have a do block involving putStrLn and getLine . isGreen ,您有一个包含putStrLngetLinedo块。 This means the function must return a value of some type IO a . 这意味着该函数必须返回IO a类型的值。 You can't get a "plain string" from it, which seems to be your intention. 您无法从中获得“纯字符串”,这似乎是您的意图。 The final line of the do block must be a monadic value, in this case an IO value - so you can't simply have a string here. do块的最后一行必须为一元数值,在这种情况下为IO值-因此,您不能在这里简单地输入字符串。

However, you can use the return function to make an IO String out of a String , as in the commented out code that "also does not work": 但是,您可以使用return函数从IO String创建IO String String ,如注释掉的代码“也不起作用”所示:

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

This works fine, and is necessary, as far as isGreen is concerned. isGreen而言,这很好,并且是必需的。 The error comes because of what happens in main . 该错误是由于main发生了什么而引起的。 You cannot print an IO value - an IO String is not actually a string, it's basically a "promise" of a future string, that will only materialise at runtime based on (in this case) the user's input. 您无法print IOIO String实际上不是字符串,它基本上是将来字符串的“承诺”,只会在运行时基于(在这种情况下)用户输入来实现。

But since main is an IO action anyway, this isn't a problem. 但是由于main仍然是IO操作,所以这不是问题。 Just do this instead: 只需这样做:

main = do
    isItGreen <- isGreen
    print isItGreen

or, completely equivalently, but imo more succinctly, 或者,完全相同,但更简洁

main = isGreen >>= print

You might prefer putStrLn to print , which when printing a string will include the enclosing quotes. 您可能更喜欢putStrLn print ,它在打印字符串时将包含引号。

Note that, if you had included a type signature for each top level value (here isGreen and main ), you'd have got more useful information from the compiler as to where the errors were. 请注意,如果您为每个顶级值(此处为isGreenmain )都包含类型签名,那么您将从编译器中获取有关错误位置的更多有用信息。

isGreen uses IO , so the type needs to be IO String , not String . isGreen使用IO ,因此类型必须是IO String ,而不是String It is an IO action that can produce a string, not a string itself. 这是一个IO操作,可以产生一个字符串,而不是字符串本身。

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

Likewise, print expects a String , not an IO String , so you need to use the IO monad instance. 同样, print需要一个String ,而不是一个IO String ,因此您需要使用IO monad实例。 (Actually, you should use putStrLn , since you don't need the implicit show that print will use.) (实际上,您应该使用putStrLn ,因为您不需要print将使用的隐式show 。)

main = isGreen >>= putStrLn

Here, >>= is creating a new IO action which will execute the IO action on the left ( isGreen ), and pass the value produced to the function on the right ( putStrLn ). 在这里, >>=正在创建一个新的 IO操作,该操作将在左侧( isGreen )执行IO操作,并将产生的值传递到右侧的函数( putStrLn )。

Since isGreen here is an IO a , you can not use if … then … else … as last line. 由于isGreen这是一个IO a ,因此if … then … else …用作最后一行。 You need to return an IO a . 您需要返回IO a

You can however use pure here (or return , although there is nothing inherently wrong with that, it ): 但是,您可以在此处使用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")

Here "Y" == take 1 (map toUpper inpStr) is more safe, since if the user has written an empty line, then head will error on the empty list. 这里"Y" == take 1 (map toUpper inpStr)更安全,因为如果用户写了空行,那么head将在空列表上出错。

Since isGreen has type IO String , then you can not use print isGreen , you here can use bind (>>=) : 由于isGreen类型为IO String ,因此您不能使用print isGreen ,因此可以在这里使用bind (>>=)

main :: IO ()
main = isGreen >>= print

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM