我正在尝试从用户那里获取输入并根据输入(从此处修改的代码)进行打印:
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)
问题在哪里,如何解决?
本质上,您的问题是使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
一个IO
值IO 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
,它在打印字符串时将包含引号。
请注意,如果您为每个顶级值(此处isGreen
和main
)都包括了一个类型签名,那么您将从编译器中获得有关错误位置的更多有用信息。
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
,因此您需要使用IO
monad实例。(实际上,你应该使用putStrLn
,因为你不需要隐含的show
是print
将使用。)
main = isGreen >>= putStrLn
Run Code Online (Sandbox Code Playgroud)
在这里,>>=
正在创建一个新 IO
动作,该IO
动作将在左侧(isGreen
)执行该动作,并将产生的值传递给右侧(putStrLn
)的函数。