-
OverloadedLists -
- Начиная с:
-
7.8.1
Включает синтаксис перегруженных списков (например, десахаризацию списков с помощью класса
IsList).
GHC поддерживает перегрузку нотации списков. Напомним нотацию для создания списков. В Haskell нотацию списков можно использовать семью следующими способами:
[] -- Empty list [x] -- x : [] [x,y,z] -- x : y : z : [] [x .. ] -- enumFrom x [x,y ..] -- enumFromThen x y [x .. y] -- enumFromTo x y [x,y .. z] -- enumFromThenTo x y z
При включённом расширении OverloadedLists приведённые выше семь видов нотации десахаризуются следующим образом:
[] -- fromListN 0 [] [x] -- fromListN 1 (x : []) [x,y,z] -- fromListN 3 (x : y : z : []) [x .. ] -- fromList (enumFrom x) [x,y ..] -- fromList (enumFromThen x y) [x .. y] -- fromList (enumFromTo x y) [x,y .. z] -- fromList (enumFromThenTo x y z)
Это расширение позволяет программистам использовать нотацию списков для создания таких структур, как Set, Map, IntMap, Vector, Text и Array. В следующем фрагменте кода приведено несколько примеров:
['0' .. '9'] :: Set Char
[1 .. 10] :: Vector Int
[("default",0), (k1,v1)] :: Map String Int
['a' .. 'z'] :: Text
Шаблоны списков также перегружаются. При включённом расширении OverloadedLists эти определения десахаризуются следующим образом:
f [] = ... -- f (toList -> []) = ... g [x,y,z] = ... -- g (toList -> [x,y,z]) = ...
(Здесь для преобразования используется синтаксис шаблонов-представлений; см. раздел Шаблоны-представления.)
6.2.9.1. Класс IsList
В приведённых выше преобразованиях функции toList, fromList и fromListN являются методами класса IsList, который экспортируется из модуля GHC.Exts. Класс типов определён следующим образом:
class IsList l where type Item l fromList :: [Item l] -> l toList :: l -> [Item l] fromListN :: Int -> [Item l] -> l fromListN _ = fromList
Класс IsList и его методы предназначены для использования вместе с расширением OverloadedLists.
- Типовая функция
Itemвозвращает тип элементов структурыl. - Функция
fromListсоздаёт структуруlиз заданного списка элементовItem l. - Функция
fromListNпринимает длину входного списка в качестве подсказки. Её поведение должно быть эквивалентноfromList. Подсказка может использоваться для более эффективного создания структурыlпо сравнению сfromList. Если заданная подсказка не равна длине входного списка, поведениеfromListNне определено. - Функция
toListдолжна быть обратной кfromList.
Вполне допустимо объявлять новые экземпляры IsList, чтобы нотация списков стала полезной для совершенно новых типов данных. Вот несколько примеров экземпляров:
instance IsList [a] where type Item [a] = a fromList = id toList = id instance (Ord a) => IsList (Set a) where type Item (Set a) = a fromList = Set.fromList toList = Set.toList instance (Ord k) => IsList (Map k v) where type Item (Map k v) = (k,v) fromList = Map.fromList toList = Map.toList instance IsList (IntMap v) where type Item (IntMap v) = (Int,v) fromList = IntMap.fromList toList = IntMap.toList instance IsList Text where type Item Text = Char fromList = Text.pack toList = Text.unpack instance IsList (Vector a) where type Item (Vector a) = a fromList = Vector.fromList fromListN = Vector.fromListN toList = Vector.toList
Однако пользователям не следует объявлять экземпляры, пересекающиеся с первым экземпляром выше. А именно, fromList и toList при применении к спискам всегда должны быть тождественными функциями. Например, следующий экземпляр запрещён:
instance {-# OVERLAPPING #-} IsList [Int] where
type Item [Int] = Int
fromList = reverse
toList = reverse
6.2.9.2. Перепривязываемый синтаксис
При десахаризации нотации списков с помощью OverloadedLists GHC использует методы fromList (и другие) из модуля GHC.Exts. Для этого не требуется импортировать GHC.Exts.
Однако при использовании RebindableSyntax GHC вместо этого использует функции, находящиеся в области видимости под именами toList, fromList и fromListN. Иными словами, эти функции можно перепривязать; ср. Перепривязываемый синтаксис и неявный импорт Prelude.
6.2.9.3. Правила выбора типов по умолчанию
В настоящее время для класса IsList не предусмотрены правила выбора типов по умолчанию. Хотя это возможно, вопрос о том, как задать смысл объявлений типов по умолчанию, таких как приведённое ниже, пока не проработан:
default ([a])
6.2.9.4. Размышления о будущем
Текущую реализацию расширения OverloadedLists можно улучшить, обрабатывая особым образом списки, состоящие только из литералов. В частности, компилятор мог бы статически размещать такие списки в компактном представлении и позволять экземплярам IsList использовать преимущества этого компактного представления. Благодаря этой возможности расширение OverloadedLists сможет заменить расширение OverloadedStrings (в настоящее время строковые литералы уже выигрывают от статически размещаемого компактного представления).