【发布时间】:2015-04-26 15:59:36
【问题描述】:
这是教科书的zip功能:
zip :: [a] -> [a] -> [(a,a)]
zip [] _ = []
zip _ [] = []
zip (x:xs) (y:ys) = (x,y) : zip xs ys
我早些时候在#haskell 上询问过“zip”是否可以单独使用“foldr”来实现,没有递归,没有模式匹配。经过一番思考,我们注意到可以使用延续来消除递归:
zip' :: [a] -> [a] -> [(a,a)]
zip' = foldr cons nil
where
cons h t (y:ys) = (h,y) : (t ys)
cons h t [] = []
nil = const []
我们还剩下模式匹配。经过更多的神经元敬酒后,我想出了一个我认为合乎逻辑的不完整答案:
zip :: [a] -> [a] -> [a]
zip a b = (zipper a) (zipper b) where
zipper = foldr (\ x xs cont -> x : cont xs) (const [])
它返回一个平面列表,但会进行压缩。我确信这是有道理的,但 Haskell 抱怨这种类型。我继续在一个无类型的 lambda 计算器上对其进行测试,它工作正常。为什么 Haskell 不能接受我的函数?
错误是:
zip.hs:17:19:
Occurs check: cannot construct the infinite type:
t0 ~ (t0 -> [a]) -> [a]
Expected type: a -> ((t0 -> [a]) -> [a]) -> (t0 -> [a]) -> [a]
Actual type: a
-> ((t0 -> [a]) -> [a]) -> (((t0 -> [a]) -> [a]) -> [a]) -> [a]
Relevant bindings include
b ∷ [a] (bound at zip.hs:17:7)
a ∷ [a] (bound at zip.hs:17:5)
zip ∷ [a] -> [a] -> [a] (bound at zip.hs:17:1)
In the first argument of ‘foldr’, namely ‘cons’
In the expression: ((foldr cons nil a) (foldr cons nil b))
zip.hs:17:38:
Occurs check: cannot construct the infinite type:
t0 ~ (t0 -> [a]) -> [a]
Expected type: a -> (t0 -> [a]) -> t0 -> [a]
Actual type: a -> (t0 -> [a]) -> ((t0 -> [a]) -> [a]) -> [a]
Relevant bindings include
b ∷ [a] (bound at zip.hs:17:7)
a ∷ [a] (bound at zip.hs:17:5)
zip ∷ [a] -> [a] -> [a] (bound at zip.hs:17:1)
In the first argument of ‘foldr’, namely ‘cons’
In the fourth argument of ‘foldr’, namely ‘(foldr cons nil b)’
【问题讨论】:
-
Haskell 给你的错误是什么?
-
如果您只遇到模式匹配,只需使用
(,)作为函数,使用head和tail而不是(y:ys) 或者if/else? -
顺便说一句:前段时间有人问了一个非常相似的问题:stackoverflow.com/questions/235148/implement-zip-using-foldr
-
仅供参考,我在后续问题中添加了 answer,从技术上讲,该问题也可以作为此问题的答案。