读取 Haskell 中的 IO 字符串和 return 自定义数据类型列表
Read IO String and return custom data type list in Haskell
我是 Haskell 的初学者,我在 IO 操作上遇到困难。在用户发送“。”之前,我应该从用户那里获取 IO 字符串。 (点)字。我将使用这些输入通过解析字符串来转换自定义数据类型,命名 Card。然后我会将卡片添加到列表中。当用户键入“。”时,我将发送整个卡片列表。 Haskell 代码如下:
readCards :: IO [Card]
readCards = return (returnCardList [])
where
returnCardList :: [Card] -> [Card]
returnCardList acc = do line <- getLine
if line == "."
then acc
else returnCardList ((convertCard (line !! 0) (line !! 1)):acc)
convertCard
是一个接受两个 char
和 return Card
的函数。还有acc
代表尾递归函数的累加器(不是必须用尾递归实现,我就选了)。
例如 returnCardList 'h' 'q'
给出 Card {suit=Hearts, rank=Queen}
然而上面的代码分区给出了一个错误:
Couldn't match type `IO' with `[]'
Expected type: [String]
Actual type: IO String
但是下面的代码(带有虚拟卡片列表)运行 正确:
readCards :: IO [Card]
readCards = return [Card {suit=Clubs, rank=King}, Card {suit=Clubs, rank=Ace}, Card {suit=Clubs, rank=Jack}]
看了很多东西都解决不了。我真的很想知道我错过了什么。
这个代码
readCards :: IO [Card]
readCards = return (returnCardList [])
是说 readCards
是一个 IO 计算,实际上并不做 IO。实际上 return something
意味着没有执行 IO,并且 something
是类型 [Card]
.
的纯值
这不是你想要的。你需要像
这样的东西
readCards :: IO [Card]
readCards = returnCardList []
因此,IO 必须由 returnCardList
完成,现在必须具有类型
returnCardList :: [Card] -> IO [Card]
-- ^^ we do perform IO here!
你自己的实现应该可以,大致
returnCardList acc = do
line <- getLine
if line == "."
then return acc
-- ^^^^^^ turn the plain value into an IO computation
else returnCardList ((convertCard (line !! 0) (line !! 1)):acc)
这可以改写如下:
returnCardList acc = do
line <- getLine
case line of
"." -> return acc
(c1:c2:_) -> returnCardList (convertCard c1 c2 : acc)
_ -> ... -- you should handle here the other cases (length < 2)
请注意,您也可以不使用 acc
参数:
returnCardList = do
line <- getLine
case line of
"." -> return []
(c1:c2:_) -> (convertCard c1 c2 :) <$> returnCardList
_ -> ... -- you should handle here the other cases (length < 2)
我是 Haskell 的初学者,我在 IO 操作上遇到困难。在用户发送“。”之前,我应该从用户那里获取 IO 字符串。 (点)字。我将使用这些输入通过解析字符串来转换自定义数据类型,命名 Card。然后我会将卡片添加到列表中。当用户键入“。”时,我将发送整个卡片列表。 Haskell 代码如下:
readCards :: IO [Card]
readCards = return (returnCardList [])
where
returnCardList :: [Card] -> [Card]
returnCardList acc = do line <- getLine
if line == "."
then acc
else returnCardList ((convertCard (line !! 0) (line !! 1)):acc)
convertCard
是一个接受两个 char
和 return Card
的函数。还有acc
代表尾递归函数的累加器(不是必须用尾递归实现,我就选了)。
例如 returnCardList 'h' 'q'
给出 Card {suit=Hearts, rank=Queen}
然而上面的代码分区给出了一个错误:
Couldn't match type `IO' with `[]'
Expected type: [String]
Actual type: IO String
但是下面的代码(带有虚拟卡片列表)运行 正确:
readCards :: IO [Card]
readCards = return [Card {suit=Clubs, rank=King}, Card {suit=Clubs, rank=Ace}, Card {suit=Clubs, rank=Jack}]
看了很多东西都解决不了。我真的很想知道我错过了什么。
这个代码
readCards :: IO [Card]
readCards = return (returnCardList [])
是说 readCards
是一个 IO 计算,实际上并不做 IO。实际上 return something
意味着没有执行 IO,并且 something
是类型 [Card]
.
这不是你想要的。你需要像
这样的东西readCards :: IO [Card]
readCards = returnCardList []
因此,IO 必须由 returnCardList
完成,现在必须具有类型
returnCardList :: [Card] -> IO [Card]
-- ^^ we do perform IO here!
你自己的实现应该可以,大致
returnCardList acc = do
line <- getLine
if line == "."
then return acc
-- ^^^^^^ turn the plain value into an IO computation
else returnCardList ((convertCard (line !! 0) (line !! 1)):acc)
这可以改写如下:
returnCardList acc = do
line <- getLine
case line of
"." -> return acc
(c1:c2:_) -> returnCardList (convertCard c1 c2 : acc)
_ -> ... -- you should handle here the other cases (length < 2)
请注意,您也可以不使用 acc
参数:
returnCardList = do
line <- getLine
case line of
"." -> return []
(c1:c2:_) -> (convertCard c1 c2 :) <$> returnCardList
_ -> ... -- you should handle here the other cases (length < 2)