Алгебраический тип данных

редактировать

В компьютерном программировании, особенно в функциональном программировании и теории типов, алгебраический тип данных является разновидностью составного типа, то есть типа, образованного путем объединения других типов.

Двумя общими классами алгебраических типов являются типы продукта (т. Е. кортежи и записи ) и типы суммы ( т. е. помеченные или непересекающиеся союзы, типы копродукции или типы вариантов).

значения типа продукта обычно содержат несколько значений, называемых полями. Все значения этого типа имеют одинаковую комбинацию типов полей. Множество всех возможных значений типа продукта - это теоретико-множественное произведение, т.е. декартово произведение, наборов всех возможных значений его типов полей.

Значения типа суммы обычно группируются в несколько классов, называемых вариантами. Значение вариантного типа обычно создается с помощью квазифункционального объекта, называемого конструктором. У каждого варианта есть собственный конструктор, который принимает указанное количество аргументов с указанными типами. Множество всех возможных значений типа суммы является теоретико-множественной суммой, т. Е. непересекающимся объединением множеств всех возможных значений его вариантов. Перечислимые типы - это особый случай типов суммы, в которых конструкторы не принимают аргументов, поскольку для каждого конструктора определено ровно одно значение.

Значения алгебраических типов анализируются с помощью сопоставления с образцом, которое идентифицирует значение по его конструктору или именам полей и извлекает данные, которые оно содержит.

Алгебраические типы данных были введены в Hope, небольшом функциональном языке программирования, разработанном в 1970-х годах в Эдинбургском университете.

Содержание
  • 1 Примеры
  • 2 Объяснение
  • 3 Теория
  • 4 Языки программирования с алгебраическими типами данных
  • 5 См. Также
  • 6 Ссылки
Примеры

Один из наиболее распространенных примеров алгебраический тип данных - односвязный список. Тип списка - это тип суммы с двумя вариантами: Nilдля пустого списка и Cons x xsдля комбинации нового элемента x со списком xs для создания нового списка. Вот пример того, как односвязный список будет объявлен в Haskell :

data List a = Nil | Минусы a (Список a)

Минусы- это сокращение от конструкции. Многие языки имеют специальный синтаксис для списков, определенных таким образом. Например, Haskell и ML используют для Nil, :или ::для Consсоответственно и квадратные скобки для целых списков. Итак, Минусы 1 (Минусы 2 (Минусы 3 Ноль))обычно записываются как 1: 2: 3:или [1,2,3]в Haskell, или как 1 :: 2 :: 3 ::или [1; 2; 3]в ML.

Для немного более сложного примера, двоичные деревья могут быть реализованы в Haskell следующим образом:

дерево данных = Empty | Leaf Int | Дерево узлов

Здесь Пустопредставляет пустое дерево, Листсодержит фрагмент данных, а Узелорганизует данные в ветви.

В большинстве языков, поддерживающих алгебраические типы данных, можно определить параметрические типы. Примеры приведены далее в этой статье.

В чем-то похожий на функцию, конструктор данных применяется к аргументам соответствующего типа, в результате чего получается экземпляр типа данных, которому принадлежит конструктор типа. Например, конструктор данных Leafлогически является функцией Int ->Tree, что означает, что передача целого числа в качестве аргумента для Leafдает значение типа Дерево. Поскольку Узелпринимает два аргумента самого типа Tree, тип данных - рекурсивный.

. Операции с алгебраическими типами данных могут быть определены с помощью сопоставления с образцом, чтобы получить аргументы. Например, рассмотрим функцию для определения глубины Дерева, заданную здесь в Haskell:

depth :: Tree ->Int depth Empty = 0 depth (Leaf n) = 1 depth (Node lr) = 1 + max (глубина l) (глубина r)

Таким образом, Treeс заданным значением depthможет быть построено с использованием любого из Empty, Leafили Nodeи должны соответствовать любому из них соответственно, чтобы иметь дело со всеми случаями. В случае Узлашаблон извлекает поддеревья lи rдля дальнейшей обработки.

Алгебраические типы данных хорошо подходят для реализации абстрактного синтаксиса. Например, следующий алгебраический тип данных описывает простой язык, представляющий числовые выражения:

data Expression = Number Int | Добавить выражение Expression | Минус Выражение Выражение | Mult Expression Expression | Выражение разделения Выражение

Элемент такого типа данных будет иметь такую ​​форму, как Mult (Добавить (Число 4) (Минус (Число 0) (Число 1))) (Число 2).

Запись функция оценки для этого языка - простое упражнение; однако возможны и более сложные преобразования. Например, этап оптимизации в компиляторе может быть записан как функция, принимающая абстрактное выражение в качестве входных данных и возвращающая оптимизированную форму.

Объяснение

Что происходит, так это то, что существует тип данных, который может быть одним из нескольких типов вещей. Каждый тип вещей связан с идентификатором, называемым конструктором, который можно рассматривать как своего рода тег для такого рода данных. Каждый конструктор может нести разные типы данных. Конструктор может не содержать данных (например, «Пустой» в приведенном выше примере) или один фрагмент данных (например, «Лист» имеет одно значение Int) или несколько фрагментов данных (например, «Узел» имеет два значения Дерева.).

Чтобы что-то сделать со значением этого алгебраического типа данных Tree, оно деконструируется с использованием процесса, называемого сопоставлением с образцом. Он включает сопоставление данных с серией шаблонов. В приведенном выше примере функции "глубина" свой аргумент соответствует трем образцам. Когда функция вызывается, она находит первый шаблон, соответствующий ее аргументу, выполняет любые привязки переменных, которые встречаются в шаблоне, и оценивает выражение, соответствующее шаблону.

Каждый шаблон выше имеет форму, которая напоминает структуру некоторого возможного значения этого типа данных. Первый шаблон просто соответствует значениям конструктора Empty. Второй шаблон соответствует значениям конструктора Leaf. Шаблоны рекурсивны, поэтому данные, связанные с этим конструктором, сопоставляются с шаблоном «n». В этом случае идентификатор в нижнем регистре представляет шаблон, который соответствует любому значению, которое затем привязывается к переменной с этим именем - в этом случае переменная «n» привязана к целочисленному значению, хранящемуся в тип данных - который будет использоваться в выражении для оценки.

Рекурсия в шаблонах в этом примере тривиальна, но возможный более сложный рекурсивный шаблон будет примерно таким: Node (Node (Leaf 4) x) (Node y (Node Empty z)). Рекурсивные шаблоны в несколько слоев используются, например, при балансировке красно-черных деревьев, что включает случаи, когда требуется рассматривать цвета в несколько слоев.

Приведенный выше пример операционально эквивалентен следующему псевдокоду:

включить (data.constructor) case Empty: вернуть 0 case Leaf: let l = data.field1 вернуть 1 case Node: let l = data.field1 let r = data.field2 return 1 + max (depth l) (depth r)

Сравнение этого с сопоставлением с образцом укажет на некоторые преимущества алгебраических типов данных и сопоставления с образцом. Первое преимущество - это безопасность типа. Псевдокод выше полагается на старание программиста, чтобы не получить доступ к field2, например, когда конструктором является Leaf. Кроме того, тип field1отличается для Leaf и Node (для Leaf это Int; для Node это Tree), поэтому система типов будет иметь трудности с присвоением ему статического типа безопасным способом в традиционной структуре данных запись. Однако при сопоставлении с образцом тип каждого извлеченного значения проверяется на основе типов, объявленных соответствующим конструктором, и сколько значений может быть извлечено, известно на основе конструктора, поэтому он не сталкивается с этими проблемами.

Во-вторых, при сопоставлении с образцом компилятор статически проверяет, все ли случаи обработаны. Если один из случаев функции глубины, описанной выше, отсутствует, компилятор выдаст предупреждение, указывающее, что случай не обрабатывается. Эта задача может показаться легкой для простых шаблонов, описанных выше, но со многими сложными рекурсивными шаблонами задача становится трудной для обработки средним человеком (или компилятором, если он должен проверять произвольные вложенные конструкции if-else). Точно так же могут быть шаблоны, которые никогда не совпадают (т.е. уже охвачены предыдущими шаблонами), и компилятор также может проверять и выдавать предупреждения для них, поскольку они могут указывать на ошибку в рассуждениях.

Не путайте эти шаблоны с шаблонами регулярных выражений, используемыми при сопоставлении строковых шаблонов. Цель аналогична: проверить, соответствует ли часть данных определенным ограничениям, и если да, извлечь соответствующие части для обработки. Однако механизм совсем другой. Этот вид сопоставления с образцом для алгебраических типов данных соответствует структурным свойствам объекта, а не символьной последовательности строк.

Теория

Общий алгебраический тип данных - это возможно рекурсивный тип суммы из типов продукта. Каждый конструктор помечает тип продукта, чтобы отделить его от других, или, если конструктор только один, тип данных является типом продукта. Кроме того, типы параметров конструктора являются факторами типа продукта. Конструктор без параметров соответствует пустому продукту. Если тип данных рекурсивный, вся сумма произведений заключена в рекурсивный тип , и каждый конструктор также переводит тип данных в рекурсивный тип.

Например, тип данных Haskell:

список данных a = Nil | Минусы a (Список a)

представлен в теории типов как λ α. μ β.1 + α × β {\ displaystyle \ lambda \ alpha. \ mu \ beta.1+ \ alpha \ times \ beta}\ lambda \ alpha. \ mu \ beta.1+ \ alpha \ times \ beta с конструкторами nil α = roll (inl ⟨⟩) {\ displaystyle \ mathrm {nil} _ {\ alpha} = \ mathrm {roll} \ (\ mathrm {inl} \ \ langle \ rangle)}\ mathrm {nil} _ {\ alpha} = \ mathrm {roll} \ (\ mathrm {inl} \ \ langle \ rangle) и cons α xl = roll (inr ⟨Икс, l⟩) {\ Displaystyle \ mathrm {cons} _ {\ alpha} \ x \ l = \ mathrm {roll} \ (\ mathrm {inr} \ \ langle x, l \ rangle)}\ mathrm {cons} _ {\ alpha} \ x \ l = \ mathrm {roll} \ (\ mathrm {inr} \ \ langle x, l \ rangle) .

Тип данных Haskell List также может быть представлен в теории типов в несколько иной форме, например: μ ϕ. λ α.1 + α × ϕ α {\ Displaystyle \ му \ фи. \ лямбда \ альфа.1+ \ альфа \ раз \ фи \ \ альфа}\ mu \ phi. \ Lambda \ alpha.1+ \ alpha \ times \ phi \ \ alpha . (Обратите внимание, как конструкции μ {\ displaystyle \ mu}\ mu и λ {\ displaystyle \ lambda}\ lambda перевернуты относительно оригинала.) Указанная исходная формация функция типа, тело которой было рекурсивным типом. Исправленная версия определяет рекурсивную функцию для типов. (Переменная типа ϕ {\ displaystyle \ phi}\ phi используется для предложения функции, а не базового типа, такого как β {\ displaystyle \ beta}\ beta , поскольку ϕ {\ displaystyle \ phi}\ phi похож на греческое f.) Теперь функция также должна быть применена ϕ {\ displaystyle \ phi}\ phi к ее типу аргумента α {\ displaystyle \ alpha}\ alpha в теле типа.

Для целей примера со списком эти две формулировки существенно не отличаются; но вторая форма позволяет выразить так называемые, т.е. те, у которых рекурсивный тип параметрически отличается от исходного. (Для получения дополнительной информации о вложенных типах данных см. Работы Ричарда Берда, Ламберта Меертенса и Росс Патерсон.)

В теории множеств эквивалентом типа суммы является непересекающееся объединение, набор, элементы которого представляют собой пары, состоящие из тега (эквивалентного конструктору) и объекта типа, соответствующего тегу (эквивалентного аргументам конструктора).

Языки программирования с алгебраическими типами данных

Многие языки программирования включают алгебраические типы данных в качестве первоклассного понятия, включая:

См. Также
Ссылки

Эта статья основана на материале, взятом из алгебраического типа данных в Бесплатный он-лайн словарь по вычислительной технике до 1 ноября 2008 г. и включен в соответствии с условиями «перелицензирования» GFDL, версия 1.3 или l атер.

Последняя правка сделана 2021-06-10 22:35:29
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте