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

Haskell IO Char和[Char]之间的匹配类型错误,haskell,types,Haskell,Types,我正在尝试从用户处获取输入,并根据输入(代码修改自): import Data.Char(toUpper) isGreen=do “绿色是你最喜欢的颜色吗?” inpStrisGreen使用IO,因此类型需要是IO String,而不是String。它是一个IO操作,可以生成字符串,而不是字符串本身 isGreen :: IO String isGreen = do putStrLn "Is green your favorite color?" inpStr <- get

我正在尝试从用户处获取输入,并根据输入(代码修改自):

import Data.Char(toUpper)
isGreen=do
“绿色是你最喜欢的颜色吗?”

inpStr
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"

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

isGreen
使用
IO
,因此类型需要是
IO 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"

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

因为
isGreen
这里是一个
ioa
,不能使用
if…then…else…
作为最后一行。您需要返回一个
IO a

但是,您可以在此处使用
pure
(或
return
,尽管这本身并没有什么问题,但它可以):


因为
是绿色的
这里有一个
IO a
,所以不能使用
if…then…else…
作为最后一行。您需要返回一个
IO a

但是,您可以在此处使用
pure
(或
return
,尽管这本身并没有什么问题,但它可以):


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

isGreen
中,有一个
do
块涉及
putStrLn
getLine
。这意味着函数必须返回某种类型的值
IO a
。你不能从中得到一个“简单的字符串”,这似乎是你的意图。
do
块的最后一行必须是一个一元值,在本例中是一个
IO
值-因此这里不能简单地有一个字符串

但是,您可以使用
return
函数从
字符串
中生成
IO字符串
,如注释掉的代码中的“也不工作”:

isGreen
而言,这工作正常,是必要的。该错误是由于在
main
中发生的情况引起的。您不能
打印
一个
IO
值-一个
IO字符串实际上不是一个字符串,它基本上是一个未来字符串的“承诺”,它只会在运行时根据用户的输入(在本例中)实现

但既然
main
是一个
IO
操作,这就不是问题。只需这样做:

main = do
    isItGreen <- isGreen
    print isItGreen
您可能更喜欢
putStrLn
而不是
print
,在打印字符串时,它将包含括起来的引号


请注意,如果您为每个顶级值(此处为
isGreen
main
)包含了一个类型签名,那么您就可以从编译器获得更多关于错误位置的有用信息。

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

isGreen
中,有一个
do
块涉及
putStrLn
getLine
。这意味着函数必须返回某种类型的值
IO a
。你不能从中得到一个“简单的字符串”,这似乎是你的意图。
do
块的最后一行必须是一个一元值,在本例中是一个
IO
值-因此这里不能简单地有一个字符串

但是,您可以使用
return
函数从
字符串
中生成
IO字符串
,如注释掉的代码中的“也不工作”:

isGreen
而言,这工作正常,是必要的。该错误是由于在
main
中发生的情况引起的。您不能
打印
一个
IO
值-一个
IO字符串实际上不是一个字符串,它基本上是一个未来字符串的“承诺”,它只会在运行时根据用户的输入(在本例中)实现

但既然
main
是一个
IO
操作,这就不是问题。只需这样做:

main = do
    isItGreen <- isGreen
    print isItGreen
您可能更喜欢
putStrLn
而不是
print
,在打印字符串时,它将包含括起来的引号


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

谢谢您的回答。为什么编译器不能忽略
IO
部分
ioa
并继续执行?@mso:a
ioa
和a
a
之间有一个根本的区别。在一些论文中,它被写为“作为核废料容器的单子”:。事实上,编译器根本不需要知道
IO
,它只是一个类型构造函数。类型系统表示
a
IO a
是不同的,因此基本上就是这样。“单子作为核废物容器”非常有趣。提到它是积极的还是消极的?单子是非常有用还是非常危险?我相信它们对于防止容易出错的代码非常有用。@rnso:非常有用。Haskell是为数不多的几种在各种副作用之间进行区分的语言之一,对于这种副作用,它使用单子(作为容器)来防止它“感染”程序的其余部分。@因此在大多数语言中,当
f()
的类型为“integer”时,
f()+f()
表达式的计算结果可能是奇数,由于副作用(如要求用户输入)。在Haskell中,如果
f()::Int
,那么
f()+f()
必须是h
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")
main :: IO ()
main = isGreen >>= print
if (toUpper (head inpStr) == 'Y') then return "YES" else return "NO" 
main = do
    isItGreen <- isGreen
    print isItGreen
main = isGreen >>= print