Haskell - 出乎意料的预期类型

时间:2014-03-22 00:52:18

标签: haskell recursion types infinite

我正在尝试在Haskell中编写一个函数,它会弹出一些已经序列化为字符串列表的项目。 (此列表表示文本文件的行 - 一行不一定是一个项目)

使用另一个函数作为参数调用该函数。此函数将关闭单个项目,并返回包含该项目和文本其余部分的元组。该函数应该递归执行此操作n次,每次添加结果列表。它返回此列表以及文本的其余部分,以用于进一步解析。

popN :: Integer -> [String] -> ([String]-> (a, [String])) -> ([a], [String])
popN n txt fun  | n == 0 = ([], txt)
                | n /= 0 = do
                    let (tp, newtxt) = fun txt
                    let newnum = n - 1
                    let (rest, after) = popN newnum newtxt fun
                    return (tp : rest, after)

当我尝试编译此代码时,出现以下错误:

Couldn't match the expected type '[String]' with actual type '([a], [String])'
In the first argument  of 'return', namely '(tp : rest, after)'

实际类型([a], [String])是我期望的类型。然而,我不明白的是[String]是预期类型的​​原因。有人可以向我解释为什么GHC希望此函数返回[String]

提前感谢您的帮助。

3 个答案:

答案 0 :(得分:5)

return采用t类型的值,并生成m t类型的值,其中m是一些monad。函数的结果是将return应用于参数的结果。那么如果结果是([a], String)类型,那么该参数必须具有哪种类型?好吧,return x生成([a], String)类型值的唯一方法是x类型为[String]m是类型构造函数{{1 (在这一点上,没有考虑到,可能在前奏中没有这样的实例)。因此,类型检查器期望参数为(,) [a]

答案 1 :(得分:0)

do用于monadic函数,但你的是纯粹的:

popN :: Integer -> [String] -> ([String]-> (a, [String])) -> ([a], [String])
popN 0 txt _ = ([], txt)
popN n txt fun = (a:as, txt'') where
    (a, txt') = fun txt
    (as, txt'') = popN (n-1) txt' fun

似乎txt充当穿过函数的状态,可以使用State monad隐藏。

type S = State [String]

popN :: Integer -> S a -> S [a]
popN 0 _ = return []
popN n m = do
    a <- m
    as <- popN (n-1) m
    return (a:as)

但这基本上是replicateM(如果您可以处理Int而不是Integer)。

答案 2 :(得分:0)

在这种情况下,你不能使用monad,因为你要返回的元组不是monad。你可以像这样使用简单的递归:

popN :: Integer -> [String] -> ([String]-> (a, [String])) -> ([a], [String])
popN 0 txt _    = ([], txt)
popN n []  _    = ([], [])
popN n txt fun  = (tp:rest, newtxt1)
    where
        (tp,   newtxt ) = fun txt
        (rest, newtxt1) = popN (n-1) newtxt fun
相关问题