关于haskell高阶函数

时间:2013-11-07 10:17:39

标签: haskell

我被要求编写一个类型为[a -> a] -> [a] -> [a]的函数“管道”,在这样的管道中,原始函数列表中的每个函数依次应用于输入的每个元素。例如,管道[(+1),(*2),pred] [1,2,3]将返回[1,3,5]

解决方案表的答案是pipeline = map . foldr (.) id,我不太明白。该解决方案如何出现?

3 个答案:

答案 0 :(得分:1)

考虑foldr的一种方法是

foldr f z xs

xs中的每个(:)替换为f,将空列表替换为z

请注意

[(+1), (*2)]

的简写
(+1) : (*2) : []

你现在应该能够看到什么

foldr (.) id   ((+1) : (*2) : [])

评估为。从中,你将能够理解整个表达。

答案 1 :(得分:1)

虽然他们实际上非常简单,但是以某种方式折叠令人困惑。特别是正确的折叠:它基本上没有别的,只是用一些替代的给定函数替换列表中的每个:,并使用init值替换列表的nil。以你的例子:

foldr (.) id [(+1),(*2),pred]
≡ foldr (.) id ( (+1) : (*2) : pred : [] )
≡                (+1) . (*2) . pred . id

所以这只是将列表中的所有函数链接到一个大的组合。

一旦你拥有了这个链,将它应用到另一个列表中的所有值都是微不足道的,这对于map来说是一个显而易见的工作。

答案 2 :(得分:0)

问题的症结在于具有类型的函数:[a -> a] -> (a -> a),即将函数列表转换为单个函数。

foldr的类型为:(b -> c -> c) -> c -> [b] -> c

让我们看看这种类型如何适合:

  • (b -> c -> c) -> c -> [b] -> c
  • b替换为(a -> a)((a -> a) -> c -> c) -> c -> [a -> a] -> c
  • c替换为(a -> a)((a -> a) -> (a -> a) -> (a -> a)) -> (a -> a) -> [a -> a] -> (a -> a)
  • 功能类型(.)(b -> c) -> (a -> b) -> a -> c,这是我们在之前签名中的第一种类型(我们的所有a),因此我们可以使用{{1}那里。
  • 对于第二部分,(.)我们可以使用(a -> a)函数。
  • 让这些符合:id我们留下(.) id部分,这就是我们需要的内容
  • 因此,[a -> a] -> (a -> a)为我们提供了foldr (.) id

之后[a -> a] -> (a -> a)部分只是将map的结果函数应用于列表的每个元素。

注意:使用白板来理解这一切,直到你的潜意识习惯这样做;)