【问题标题】:Read IO String and return custom data type list in Haskell在 Haskell 中读取 IO 字符串并返回自定义数据类型列表
【发布时间】:2018-09-16 17:55:21
【问题描述】:

我是 Haskell 的初学者,我在 IO 操作方面遇到了困难。我应该从用户那里获取 IO 字符串,直到用户发送“。” (点)字。我将使用这些输入通过解析字符串来转换自定义数据类型、命名卡。然后我会将卡片添加到列表中。当用户键入“。”时,我将发送整个卡片列表。 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 并返回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}]

我读了很多东西,但我无法解决它。我真的很想知道我想念什么。

【问题讨论】:

标签: haskell recursion io tail-recursion


【解决方案1】:

这段代码

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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-15
    • 2013-03-16
    • 2012-02-18
    • 1970-01-01
    相关资源
    最近更新 更多