读取IO String并在Haskell中返回自定义数据类型列表

时间:2018-04-06 16:29:55

标签: haskell recursion io tail-recursion

我是Haskell的初学者,我在与IO操作斗争。我应该从用户那里获得IO String,直到用户发送“。” (点)性格。我将使用这些输入来转换自定义数据类型,命名卡,通过解析字符串。然后我将卡添加到列表中。当用户输入“。”时,我将发送整个卡片列表。 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}]

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

1 个答案:

答案 0 :(得分: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) 参数:

{{1}}