我被要求编写一个类型为[a -> a] -> [a] -> [a]
的函数“管道”,在这样的管道中,原始函数列表中的每个函数依次应用于输入的每个元素。例如,管道[(+1),(*2),pred]
[1,2,3]
将返回[1,3,5]
。
解决方案表的答案是pipeline = map . foldr (.) id
,我不太明白。该解决方案如何出现?
答案 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
的结果函数应用于列表的每个元素。
注意:使用白板来理解这一切,直到你的潜意识习惯这样做;)