简体   繁体   English

了解 Data.List.Extra 库中的 groupSort 和 groupOn 函数

[英]Understanding groupSort and groupOn functions in Data.List.Extra library

These are the definitions of groupSort and groupOn in Data.List.Extra module:这些是Data.List.Extra模块中groupSortgroupOn的定义:

groupSort :: Ord k => [(k, v)] -> [(k, [v])]
groupSort = map (\x -> (fst $ head x, map snd x)) . groupOn fst . sortOn fst
groupOn :: Eq b => (a -> b) -> [a] -> [[a]]
groupOn f = groupBy ((==) `on2` f)
    -- redefine on so we avoid duplicate computation for most values.
    where (.*.) `on2` f = \x -> let fx = f x in \y -> fx .*. f y

I would like to know:我想知道:

  • What's the meaning of the comma in (fst $ head x, map snd x) ? (fst $ head x, map snd x)中的逗号是什么意思?
  • What's the meaning of (.*.) inside the definition of groupOn ? groupOn的定义中(.*.)的含义是什么?
  • Why is function on redefined ?为什么功能on重新定义? Why is duplicate computation avoided ?为什么要避免重复计算?

What's the meaning of the comma in (fst $ head x, map snd x) ? (fst $ head x, map snd x)中的逗号是什么意思?

It's just a tuple, exactly the same as in something like (1, 2) .它只是一个元组,与(1, 2)类的内容完全相同。 (It might be clearer to rewrite it as (fst (head x), map snd x) .) (将其重写为(fst (head x), map snd x)可能更清楚。)

What's the meaning of (.*.) inside the definition of groupOn ? groupOn的定义中(.*.)的含义是什么?

It's just a particularly clever (though not particularly readable) way of defining the first argument of on2 .这只是定义on2的第一个参数的一种特别聪明(虽然不是特别易读)的方式。 That is, the following two definitions are equivalent:也就是说,以下两个定义是等价的:

(.*.) `on2` f = \x -> let fx = f x in \y -> fx .*. f y
g     `on2` f = \x -> let fx = f x in \y -> fx `g` (f y)

Why is function on redefined ?为什么功能on重新定义? Why is duplicate computation avoided ?为什么要避免重复计算?

I'm honestly not sure… I can see no particular advantages to redefining on here.老实说,我不确定……我看不出on这里重新定义有什么特别的好处。 (I'm not even sure what 'duplicate computation' they're talking about! If someone else has any idea why they're doing this, feel free to add a comment.) (我什至不确定他们在谈论什么“重复计算”!如果其他人知道他们为什么这样做,请随时添加评论。)

What's the meaning of the comma in (fst $ head x, map snd x) (fst $ head x, map snd x)中的逗号是什么意思

it constructs a 2-tuple, with fst (head x) as first item, and map snd x as second item.它构造了一个 2 元组,将fst (head x)作为第一项,并将map snd x为第二项。 The lambda expression \\x -> (fst $ head x, map snd x) thus pas a list of values of the group to a 2-tuple where the first item is the first item of the first 2-tuple of the list, and the second item is a list of all the second item of the list of 2-tuples xs . lambda 表达式\\x -> (fst $ head x, map snd x)因此将组的值列表传递给一个 2 元组,其中第一项是列表的第一个 2 元组的第一项,并且第二项是二元组xs列表的所有第二项的列表。

What's the meaning of (.*.) inside the definition of groupOn ? groupOn的定义中(.*.)的含义是什么?

It is the first operand of the on2 function that is defined in the where clause.它是在 where 子句中定义的on2函数的第一个操作数。 One could have defined it with:人们可以用以下方式定义它:

where on2 g f = \x -> let fx = f x in \y -> g fx (f y)

Here we thus renamed the first parameter g , and since it is not an operator, we thus do not use infix notation like fx .*. fy在这里,我们因此重命名了第一个参数g ,并且由于它不是运算符,因此我们不使用像fx .*. fy这样的中缀符号fx .*. fy fx .*. fy , but write g fx (fy) . fx .*. fy ,但写g fx (fy)

In case of the groupBy , then (.*.) is thus the same as (==) , and this thus means that (==) `on2` f is the same as:groupBy情况下,则(.*.)因此与(==)相同,这意味着(==) `on2` f与:

(==) `on2` f = \x -> let fx = f x in \y -> fx == f y

It is thus a function that determines when two items are considered to be in the same group.因此,它是一个确定何时将两个项目视为在同一组中的函数。

Why is function on redefined?为什么功能on重新定义? Why is duplicate computation avoided?为什么要避免重复计算?

It aims to avoid computing f on the first item multiple times.它旨在避免在第一项上多次计算f It does this once, and stores this in a variable fx to avoid recomputing it for each next element where we want to check if it belongs to same group.它执行一次,并将其存储在变量fx以避免为我们想要检查它是否属于同一组的每个下一个元素重新计算它。

The groupBy function is implemented as [src] : groupBy函数实现为 [src]

groupBy                 :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy _  []           =  []
groupBy eq (x:xs)       =  (x:ys) : groupBy eq zs
                           where (ys,zs) = span (eq x) xs

Here it will thus calculate eq x to generate a function that matches the following elements.在这里它将因此计算eq x以生成与以下元素匹配的函数。 By calling eq x , it will thus call the function with the first item of the group that it is constructing, and the let statements will ensure that let fx = fx in … , this thus means that fx is no longer calculated.通过调用eq x ,它将因此调用具有它正在构造的组的第一项的函数,并且let语句将确保let fx = fx in … ,这意味着不再计算fx

Of course on2 will still evaluate fx for all the next elements that will be matched to the group.当然, on2仍会为将与该组匹配的所有下一个元素评估fx This thus means that if you are writing:因此,这意味着如果您正在编写:

groupOn (+1) [1,1,1,1,1,2,2,2,2,2,1,1,1,1]

it will check the following elements of the list, we will evaluate this as fx :它将检查列表的以下元素,我们将其评估为fx

             [1,        2,        1      ]

For the following elements we will evaluate this as fy :对于以下元素,我们将其评估为fy

             [  1,1,1,1,2,2,2,2,2,1,1,1,1]

as second operand.作为第二个操作数。 So we still evaluate f on each element of the list at least once, and for each start of a new group (except the first one) we will evaluate it twice.所以我们仍然至少对列表的每个元素评估f一次,并且对于新组的每个开始(除了第一个)我们将评估它两次。

For a list of n elements with n>0 that is divided in g groups, it will evaluate f n+g-1 times.对于n>0n 个元素的列表,该列表被划分为g组,它将计算f n+g-1次。

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

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