我有一个非常基本的Haskell功能。 它应该预先添加一个元组列表,如果不存在则返回它。 添加元组需要在前置之前进行编辑。
我期待一个类型如下的函数:
Num t => (a, t) -> [(a, t)] -> [(a, t)]
功能是这样的:
update x lst
| hasElement x lst == True = addElement x lst
| otherwise = lst
where hasElement element list = not (null (filter ((==element).fst) list))
addElement a b = (fst a, (snd a) +1) : b
但是当我尝试加载模块时遇到错误:
• Occurs check: cannot construct the infinite type: a ~ (a, t)
Expected type: [(a, t)]
Actual type: [((a, t), t)]
• In the second argument of ‘addElement’, namely ‘lst’
In the expression: addElement x lst
In an equation for ‘update’:
update x lst
| hasElement x lst == True = addElement x lst
| otherwise = lst
where
hasElement element list
= not (null (filter ((== element) . fst) list))
addElement a b = (fst a, (snd a) + 1) : b
• Relevant bindings include
lst :: [((a, t), t)] (bound at pip.hs:40:10)
x :: (a, t) (bound at pip.hs:40:8)
update :: (a, t) -> [((a, t), t)] -> [(a, t)]
(bound at pip.hs:40:1)
addElement 返回类型似乎全部崩溃,因为将其注释掉会使模块正常工作。
问题是:出了什么问题? 单独尝试功能似乎正如我所料。
谢谢, FB
答案 0 :(得分:1)
该特定错误的原因是element
包含密钥和值,但是(==element) . fst
您尝试仅比较密钥。
实际获取密钥的最佳方法是在函数参数中对模式进行匹配。请注意,您根本不需要element
变量,也不需要本地函数的其他参数:
update (key,y) lst
| hasElement = addElement -- comparing `==True` is a no-op!
| otherwise = lst
where hasElement = not . null $ filter ((==key).fst) lst
addElement = (key, y+1) : b
我怀疑addElement
的这种行为是否真的是你想要的:你不是用给定的密钥更新现有元素,而是添加一个具有相同密钥的新元素?
此外,not
,null
和filter
的组合不必要地复杂化。你可以使用
hasElement = any ((==key).fst) lst
最后,签名Num a => ...
实际上还不够强大:您正在将密钥与==
进行比较。仅当密钥具有Eq
实例时才有效。所以,这是正确的签名:
(Eq a, Num t) => (a, t) -> [(a, t)] -> [(a, t)]