[英]Understanding groupSort and groupOn functions in Data.List.Extra library
这些是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
我想知道:
(fst $ head x, map snd x)
中的逗号是什么意思?groupOn
的定义中(.*.)
的含义是什么?on
重新定义? 为什么要避免重复计算?
(fst $ head x, map snd x)
中的逗号是什么意思?
它只是一个元组,与(1, 2)
类的内容完全相同。 (将其重写为(fst (head x), map snd x)
可能更清楚。)
groupOn
的定义中(.*.)
的含义是什么?
这只是定义on2
的第一个参数的一种特别聪明(虽然不是特别易读)的方式。 也就是说,以下两个定义是等价的:
(.*.) `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)
为什么功能
on
重新定义? 为什么要避免重复计算?
老实说,我不确定……我看不出on
这里重新定义有什么特别的好处。 (我什至不确定他们在谈论什么“重复计算”!如果其他人知道他们为什么这样做,请随时添加评论。)
(fst $ head x, map snd x)
中的逗号是什么意思
它构造了一个 2 元组,将fst (head x)
作为第一项,并将map snd x
为第二项。 lambda 表达式\\x -> (fst $ head x, map snd x)
因此将组的值列表传递给一个 2 元组,其中第一项是列表的第一个 2 元组的第一项,并且第二项是二元组xs
列表的所有第二项的列表。
groupOn
的定义中(.*.)
的含义是什么?
它是在 where 子句中定义的on2
函数的第一个操作数。 人们可以用以下方式定义它:
where on2 g f = \x -> let fx = f x in \y -> g fx (f y)
在这里,我们因此重命名了第一个参数g
,并且由于它不是运算符,因此我们不使用像fx .*. fy
这样的中缀符号fx .*. fy
fx .*. fy
,但写g fx (fy)
。
在groupBy
情况下,则(.*.)
因此与(==)
相同,这意味着(==) `on2` f
与:
(==) `on2` f = \x -> let fx = f x in \y -> fx == f y
因此,它是一个确定何时将两个项目视为在同一组中的函数。
为什么功能
on
重新定义? 为什么要避免重复计算?
它旨在避免在第一项上多次计算f
。 它执行一次,并将其存储在变量fx
以避免为我们想要检查它是否属于同一组的每个下一个元素重新计算它。
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
在这里它将因此计算eq x
以生成与以下元素匹配的函数。 通过调用eq x
,它将因此调用具有它正在构造的组的第一项的函数,并且let
语句将确保let fx = fx in …
,这意味着不再计算fx
。
当然, on2
仍会为将与该组匹配的所有下一个元素评估fx
。 因此,这意味着如果您正在编写:
groupOn (+1) [1,1,1,1,1,2,2,2,2,2,1,1,1,1]
它将检查列表的以下元素,我们将其评估为fx
:
[1, 2, 1 ]
对于以下元素,我们将其评估为fy
:
[ 1,1,1,1,2,2,2,2,2,1,1,1,1]
作为第二个操作数。 所以我们仍然至少对列表的每个元素评估f
一次,并且对于新组的每个开始(除了第一个)我们将评估它两次。
对于n>0的n 个元素的列表,该列表被划分为g组,它将计算f
n+g-1次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.