-
TransformListComp -
- Начиная с:
-
6.10.1
Разрешает использовать синтаксис обобщённых списковых включений (в стиле SQL). Добавляет ключевые слова
group,byиusing.
Обобщённые списковые включения — это дальнейшее усовершенствование синтаксического сахара для списковых включений, позволяющее выполнять такие операции, как сортировка и группировка, знакомые по SQL. Они подробно описаны в статье Подробное рассмотрение списковых включений: включения с «order by» и «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 имела тип forall 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",...]