Главная » Haskell » Изоморфные типы

0

В языке Haskell, который, как известно, является нестрогим, ошибочные вычисления и вычисления, которые  не могут быть  остановлены (например, бес-

конечная рекурсия без точки выхода), обозначаются символом (?). Этот символ

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

чений (?).

Кроме того, для алгебраических типов данных невозможно определить  более одного экземпляра заданного класса (этот вопрос будет детально раскрыт далее), а для синонимов типов экземпляры вообще определять нельзя. Поэтому нет возможности описать иное поведение для значений некоторого типа данных, если такое поведение через некоторый класс уже описано. Это накладывает  определённые ограничения, которые не всегда позволяют разработчику программного обеспечения выразить те идеи, которые он желает.

Для  решения указанных  проблем в  языке  Haskell имеется  возможность для определения изоморфных типов данных, то есть таких, которые тождествен-

ны с некоторым типом относительно множества значений.   определяются с помощью ключевого слова newtype. Например:

newtype PointsList =  PL [Point3D]

В этом определении после ключевого слова newtype стоит наименование изоморфного типа, после которого через символ определения (=) записывается конструктор изоморфного типа и тип данных, для которого определяется этот изоморфный тип. В приведённом выше определении записано, что тип PointsList является в точности списком на значениях типа Point3D. Для создания значений этого типа используется конструктор данных PL.

Резонный вопрос, почему не определить то же самое как синоним или даже новый алгебраический тип данных? Например, вот так:

type  PointsListS  = [Point3D]

data  PointsListADT =  PLadt  [Point3D]

Про синоним типов PointsListS даже  не стоит говорить, ибо,  как сказано ранее, это просто новое наименование для типа  [Point3D], не более. Для синонимов происходит простая синтаксическая замена там, где они встречаются. Для понимания различия конструкторов PL и PLadt необходимо ввести ещё два определения:

f1  (PL  _)  =  []

f2  (PLadt  _)  =  []

И вот здесь и кроется кардинальное отличие. Если конструкторам PL и PLadt

передать в качестве входного параметра  неопределённое значение (?), а затем

полученные данные передать на вход функциям f1  и f2 соответственно, то результаты их выполнения будут различаться.  Если вызов f2  (PLadt  ?)  вернёт пустой список [], то вызов f1  (PL  ?) вернёт значение (?). Другими словами, (N ?) всегда эквивалентен (?), а (D ?) неэквивалентен (?), если только кон-

структор D не строгий (здесь:  N — конструктор изоморфного типа, D — конструктор алгебраического типа данных).

Источник: Душкин Р. В., Справочник по языку Haskell. М.: ДМК Пресс, 2008. 544 с., ил.

По теме:

  • Комментарии