我正在尝试在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 回答
return
采用t
类型的值并生成m t
类型的值,其中m
是某个monad . 函数的结果是将return
应用于参数的结果 . 那么如果结果是([a], String)
类型,那么该参数必须具有哪种类型?好吧,return x
可以产生([a], String)
类型值的唯一方法是x
类型为[String]
而m
是类型构造函数(,) [a]
(没有考虑到,此时可能没有这样的实例存在于前奏中) . 因此,类型检查器期望参数为[String]
.在这种情况下,您不能使用monad,因为您返回的元组不是monad . 你可以像这样使用简单的递归:
do
用于monadic函数,但是你的纯函数是:似乎
txt
正在充当穿过该函数的状态,并且可以使用State
monad隐藏 .但这基本上是
replicateM
(如果你可以处理Int
而不是Integer
) .