我无法理解fold
和foldr
之间的区别。
fold
的定义是:
fold :: (t->t->t) -> [t] -> t
fold f [a] = a
fold f (a:b:x)= f a (fold f (b:x))
其中只有一个类型参数t
foldr
定义为
foldr :: (t->u->u) -> u -> [t] -> u
foldr f s [] = s
foldr f s (a:x) = f a (foldr f s x)
我正在阅读"功能编程技巧"并且它表示通过添加额外的参数来修改fold
函数以检查空列表。当foldr
函数本身可以被修改以满足所有目的时,为什么需要fold
这是没有意义的。
其次,当我从书中尝试以下示例时:
rev :: [t] -> [t]
rev list = foldr stick [] list
stick :: t -> [t] -> [t]
stick a x = x++[a]
并将foldr
的定义修改为foldr::(t->t->t)->[t]->t
。 Hugs抛出了一个无限统一类型的错误。我尝试使用谷歌搜索,但找不到满意的答案。
总结我的怀疑如下:
foldr
类型比折叠更普遍的原因。答案 0 :(得分:2)
我将从最后开始:
rev :: [t] -> [t]
rev list = foldr stick [] list
stick :: t -> [t] -> [t]
stick a x = x ++ [a]
如果您使用foldr
的定义,将会正常工作:
foldr :: (t->u->u) -> u -> [t] -> u
foldr f s [] = s
foldr f s (a:x) = f a (foldr f s x)
你可以在这里看到:
λ> rev [1..5]
[5,4,3,2,1]
如果您将其替换为fold
:
fold :: (t->t->t) -> [t] -> t
无论你如何命名,因为问题都是从签名开始的。
请参阅 - 当您执行rev list = fold stick [] list
时,您会说
t -> t -> t
应该以某种方式等于
t' -> [t'] -> [t']
第一个是类型fold
期望它的第一个参数,第二个是stick
给出的签名(重命名为{{1} } t
这里表示类型可能不同。)
现在这意味着t'
和t ~ t'
或t ~ [t']
这很可能是你得到的错误(顺便说一下:t ~ [t]
这里是我说 2类型a ~ b
和a
应该相等 - 如果您愿意,请考虑b
这应该可以解释你的怀疑2 我希望
现在到第一部分:说实话,我不知道应该告诉你什么。
让=
更加通用的原因是它的更通用 - 确实fold
对于列表来说是一个非常特殊的函数 - 它是{{ 3}}(另见the list catamorphism)
但复杂 复杂 一般功能在列表上操作
实际上,您可以在列表中重写大量函数(基本上是使用 empty或cons 样式中的模式匹配的递归函数),只有foldr
- 这很可能是你课程的一个重要部分(我认为你是FP101x的学生吗?)和你的书 - 因为它的示例用于高阶函数来统治他们都是;)