Haskell多态定义

时间:2015-11-17 04:39:17

标签: haskell

我无法理解foldfoldr之间的区别。 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抛出了一个无限统一类型的错误。我尝试使用谷歌搜索,但找不到满意的答案。

总结我的怀疑如下:

  • 疑问1:使foldr类型比折叠更普遍的原因。
  • 疑问2:为什么我会得到一个错误,即无限统一类型。

1 个答案:

答案 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 ~ ba应该相等 - 如果您愿意,请考虑b

这应该可以解释你的怀疑2 我希望

现在到第一部分:说实话,我不知道应该告诉你什么。

=更加通用的原因是它的更通用 - 确实fold对于列表来说是一个非常特殊的函数 - 它是{{ 3}}(另见the list catamorphism

复杂 复杂 一般功能在列表上操作

实际上,您可以在列表中重写大量函数(基本上是使用 empty或cons 样式中的模式匹配的递归函数),只有foldr - 这很可能是你课程的一个重要部分(我认为你是FP101x的学生吗?)和你的书 - 因为它的示例用于高阶函数来统治他们都是;)