[英]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
模块中groupSort
和groupOn
的定义:
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:我想知道:
(fst $ head x, map snd x)
? (fst $ head x, map snd x)
中的逗号是什么意思?(.*.)
inside the definition of groupOn
? groupOn
的定义中(.*.)
的含义是什么?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 ofgroupOn
?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 ofgroupOn
?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>0的n 个元素的列表,该列表被划分为g组,它将计算
f
n+g-1次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.