我正在尝试从用户那里获取输入并根据输入(从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 }
问题出在哪里,如何解决?
答案 0 :(得分:8)
本质上,您的问题是将IO
代码与非IO代码或“纯”代码混淆。
在isGreen
中,您有一个do
块,涉及putStrLn
和getLine
。这意味着函数必须返回某个类型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
,它在打印字符串时将包含引号。
请注意,如果您为每个顶级值(此处为print
和isGreen
)都包含了类型签名,那么您将从编译器中获得有关错误发生位置的更多有用信息。
答案 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
:
(>>=)