-
TransformListComp -
- Since:
-
6.10.1
Разрешает использование синтаксиса обобщённых списочных включений (похожих на SQL). Это вводит ключевые слова
group,by, иusing.
Обобщённые списочные включения представляют собой дальнейшее улучшение синтаксического сахара списочных включений, позволяющее выполнять такие операции, как сортировка и группировка, знакомые по SQL. Они подробно описаны в документе Comprehensive comprehensions: comprehensions with “order by” and “group by”, за исключением того, что используемый нами синтаксис немного отличается от синтаксиса в документе.
Расширение включено с расширением TransformListComp.
Вот пример:
employees = [ ("Simon", "MS", 80)
, ("Erik", "MS", 100)
, ("Phil", "Ed", 40)
, ("Gordon", "Ed", 45)
, ("Paul", "Yale", 60) ]
output = [ (the dept, sum salary)
| (name, dept, salary) <- employees
, then group by dept using groupWith
, then sortWith by (sum salary)
, then take 5 ]
В этом примере список output будет иметь значение:
[("Yale", 60), ("Ed", 85), ("MS", 180)]
Существует три новых ключевых слова: group, by, и using. (Функции sortWith и groupWith не являются ключевыми словами; это обычные функции, экспортируемые GHC.Exts.)
Существует пять новых форм квалификатора включения, все они вводятся (существующим) ключевым словом then:
-
then f
Это утверждение требует, чтобы f имело тип для всех a. [a] -> [a]. Вы можете увидеть пример его использования в примере, поскольку эта форма используется для применения take 5.
-
then f by e
Эта форма похожа на предыдущую, но позволяет создать функцию, которая будет передана в качестве первого аргумента в f. Вследствие этого f должно иметь тип
forall a. (a -> t) -> [a] -> [a]. Как видно из типа, эта функция позволяет f «извлекать» некоторую информацию из элементов списка, который он преобразует.Пример показан в открывающем примере, где
sortWithснабжена функцией, которая позволяет ей узнатьsum salaryдля любого элемента в списочном включении, которое она преобразует. -
then group by e using f
Это самое общее из утверждений типа группировки. В этой форме f должно иметь тип
forall a. (a -> t) -> [a] -> [[a]]. Как и в случае сthen f by eвыше, первый аргумент — функция, предоставляемая компилятором f, которая позволяет ей вычислить e для каждого элемента преобразуемого списка. Однако в отличие от случая без группировки, f дополнительно разделяет список на несколько подсписков: это означает, что в любой момент после этого утверждения связывающие переменные, предшествующие ему в включении, ссылаются на списки возможных значений, а не на отдельные значения. Чтобы помочь понять это, давайте посмотрим на пример:-- This works similarly to groupWith in GHC.Exts, but doesn't sort its input first groupRuns :: Eq b => (a -> b) -> [a] -> [[a]] groupRuns f = groupBy (\x y -> f x == f y) output = [ (the x, y) | x <- ([1..3] ++ [1..2]) , y <- [4..6] , then group by x using groupRuns ]
В результате переменная
outputпринимает значение ниже:[(1, [4, 5, 6]), (2, [4, 5, 6]), (3, [4, 5, 6]), (1, [4, 5, 6]), (2, [4, 5, 6])]
Обратите внимание, что мы использовали функцию
theдля изменения типа x со списка на его исходный числовой тип. Переменная y, напротив, остаётся неизменной в форме списка, введённой группировкой. -
then group using f
С этой формой группового утверждения f должно иметь просто тип
forall a. [a] -> [[a]], который будет непосредственно использоваться для группировки включения до сих пор. Пример использования этой формы приведён ниже:output = [ x | y <- [1..5] , x <- "hello" , then group using inits]
Это даст список, содержащий каждый префикс слова «hello», написанный 5 раз:
["","h","he","hel","hell","hello","helloh","hellohe","hellohel","hellohell","hellohello","hellohelloh",...]