简体   繁体   English

地图。 foldr函数组合 - Haskell

[英]map . foldr function composition - Haskell

So, let's straight to the point. 所以,让我们直截了当。

:t (map.foldr)
(map.foldr) :: (a1 -> a -> a) -> [a] -> [[a1] -> a]

What is [[a1] -> a]? 什么是[[a1] - > a]? I'm really trying to understand this composition, so I was doing this: 我真的想要理解这个构图,所以我这样做:

-- map.foldr

    map.foldr :: (a1 -> a -> a) -> [a] -> [[a1] -> a]

    map :: (a1 -> b1) -> [a1] -> [b1]
    (.) :: (y -> w) -> (x -> y) -> x -> w
    foldr :: (a -> b -> b) -> b -> [a] -> b

    y = (a1 -> b1)      w = ([a1] -> [b1])
    x = (a -> b -> b)   y = (b -> [a] -> b)

    y = (a1 -> b1)  
    y = (b -> [a] -> b)
_________________________

What happens in this point? 在这一点上会发生什么? Thank you! 谢谢!

To answer this question it's good to recall what foldr and map do. 要回答这个问题,最好回想一下foldrmap作用。

The more complicated of the two is foldr , which has type 两者中较为复杂的是foldr ,它有类型

--              list to be folded
--                              v
foldr :: (a -> b -> b) -> b -> [a] -> b
--             ^          ^
--folding function        terminal value

The list to be folded is really a chain of conses (:) and a terminal empty list: 要折叠的列表实际上是一个conses链(:)和一个终端空列表:

1 : 2 : 3 : []

The action of foldr is to replace the : and [] constructors with the folding function and the terminal value, respectively: foldr的作用是分别用折叠函数和终值替换:[]构造函数:

foldr (+) 0 (1 : 2 : 3 : []) == 1 + 2 + 3 + 0

The map function is simpler. map功能更简单。 One way of thinking of it is as taking a function and a list, and applying the function to every argument of the list: 考虑它的一种方法是获取函数和列表,并将函数应用于列表的每个参数:

map :: (a -> b) -> [a] -> [b]
--        ^         ^
-- function         list

However, you can also think of it as taking a function, and lifting it to be a function that acts on lists instead: 但是,您也可以将其视为一个函数,并将其提升为一个对列表起作用的函数:

map :: (a -> b) -> ( [a] -> [b] )
--        ^              ^
-- function              function on lists

What does it mean to compose these two functions, map . foldr map . foldr这两个函数是什么意思map . foldr map . foldr ? map . foldr Note that this is just applying the functions one after the other - in particular, 请注意,这只是一个接一个地应用这些功能 - 特别是

(map . foldr) f == map (foldr f)

Since you apply foldr first, you must be applying it to a function f :: a -> b -> b , and you get back another function: 因为你首先应用foldr ,你必须将它应用于函数f :: a -> b -> b ,然后你得到另一个函数:

foldr f :: b -> [a] -> b
--         ^     ^
--terminal val   list to be folded

Now you apply map , which lifts the function to act on lists: 现在您应用map ,它将提升函数以对列表执行操作:

map (foldr f) :: [b] -> [[a] -> b]
--                ^          ^
--list of terminal vals      functions that fold lists

This type looks odd, but it's valid. 这种类型看起来很奇怪,但它是有效的。 Now instead of a single terminal value, you give it a list of terminal values, and you get a list of folding functions back - one for each terminal value that you supplied. 现在,不是单个终端值,而是给它一个终端值列表,然后返回折叠函数列表 - 每个终端值对应一个。


To make it clearer we could look at a particular function, (+) , which has type 为了更清楚,我们可以查看具有类型的特定函数(+)

(+) :: Num a => a -> a -> a

If we substitute that into the equation above, we get 如果我们将其替换为上面的等式,我们得到

(map . foldr) (+) :: Num a => [a] -> [[a] -> a]
--                             ^          ^
--         list of terminal vals          functions that fold lists

If we now apply it to the list [0, 1, 2] we get a list of three functions: 如果我们现在将它应用于列表[0, 1, 2]我们将得到三个函数的列表:

(map . foldr) (+) [0,1,2] :: Num a => [[a] -> a]

We can use the map ($x) idiom to apply each of the functions in the list to a particular argument. 我们可以使用map ($x) idiom将列表中的每个函数应用于特定参数。 It has to be a list of numbers, and I'll choose [3,4,5] . 它必须是一个数字列表,我将选择[3,4,5] Watch carefully: 仔细观察:

> map ($[3,4,5]) ((map.foldr) (+) [0,1,2])
[12, 13, 14]

The list [3,4,5] was folded three times using (+) as the folding function, and each time with a different terminal value: 使用(+)作为折叠函数将列表[3,4,5]折叠三次,并且每次使用不同的终值:

3 + 4 + 5 + 0 == 12
3 + 4 + 5 + 1 == 13
3 + 4 + 5 + 2 == 14

When the terminal value is 0 , we simply get the sum of the values: 3 + 4 + 5 == 12 . 当终端值为0 ,我们只需得到值的总和: 3 + 4 + 5 == 12 When the terminal value is 1 we get one more than the sum of the values ( 13 ) and when the terminal value is 2 we get two more than the sum of the values ( 14 ). 当终值为1我们得到的值多于值的总和( 13 ),当终值为2我们得到的值比值的总和( 14 )多两个。

To continue where you left off, the two definitions of y must be equal: 要从中断的地方继续, y的两个定义必须相等:

y = (a1 -> b1) = (b ->  [a] -> b)
               = (b -> ([a] -> b))

so we can conclude that: 所以我们可以得出结论:

a1 = b
b1 = [a] -> b

The function composition has been supplied two function arguments, so the resulting type is just: 函数组合已经提供了两个函数参数,因此结果类型只是:

x -> w

But we know: 但我们知道:

x = a -> b -> b
w = [a1] -> [b1] = [b] -> [[a] -> b]

So, the result type is: 所以,结果类型是:

(x -> w) = ((a -> b -> b) -> ([b] -> [[a] -> b]))
         =  (a -> b -> b) ->  [b] -> [[a] -> b]

which is congruent to: 这与以下内容一致:

(a1 -> a -> a) -> [a] -> [[a1] -> a]
map.foldr :: (a1 -> a -> a) -> [a] -> [[a1] -> a]

map :: (a1 -> b1) -> [a1] -> [b1]
(.) :: (y -> w) -> (x -> y) -> x -> w
foldr :: (a -> b -> b) -> b -> [a] -> b

-- if you substitute: x = (a -> b -> b)   y = (b -> [a] -> b)
-- then you get for map :: (b -> ([a] -> b)) -> [b] -> [[a] -> b]
-- so if composition operator applied:
map . foldr :: (a -> b -> b) -> [b] -> [[a] -> b]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM