stringtranslate.com

Тип класса

В информатике класс типов — это конструкция системы типов , поддерживающая специальный полиморфизм . Это достигается за счет добавления ограничений на переменные типа в параметрически полиморфных типах. Такое ограничение обычно включает класс типа Tи переменную типа a и означает, что его aэкземпляр может быть создан только для типа, члены которого поддерживают перегруженные операции, связанные с T.

Классы типов были впервые реализованы на языке программирования Haskell после того, как они были впервые предложены Филипом Уодлером и Стивеном Блоттом в качестве расширения «eqtypes» в Standard ML , [1] [2] и первоначально были задуманы как способ реализации перегруженной арифметики и равенства. операторы в принципиальном порядке. [3] [2] В отличие от «eqtypes» Standard ML, перегрузка оператора равенства посредством использования классов типов в Haskell не требует обширной модификации интерфейса компилятора или базовой системы типов. [4]

Обзор

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

class Eq a где ( == ) :: a -> a -> Bool ( /= ) :: a -> a -> Bool                 

где a— один экземпляр класса типов Eqи aопределяет сигнатуры функций для двух функций (функций равенства и неравенства), каждая из которых принимает по два аргумента типа aи возвращает логическое значение.

Переменная типа aимеет вид ( также известный как в последней версии GHC ), [5] что означает, что типTypeEq

Eq :: Тип -> Ограничение    

Объявление можно прочитать как заявление о том, что «тип aпринадлежит классу типов , Eqесли на нем определены функции с именами (==)и (/=)соответствующих типов». Затем программист может определить функцию elem(которая определяет, находится ли элемент в списке) следующим образом:

elem :: Eq a => a -> [ a ] ​​-> Bool elem y [] = False elem y ( x : xs ) = ( x == y ) || элемент y хз                       

Функция elemимеет тип a -> [a] -> Boolс контекстом Eq a, который ограничивает типы, которые aмогут варьироваться до тех a, которые принадлежат Eqклассу типов. ( Примечание : Haskell => можно назвать «ограничением класса».)

Программист может сделать любой тип tчленом данного класса типов, Cиспользуя объявление экземпляра , определяющее реализации всех Cметодов для конкретного типа t. Например, если программист определяет новый тип данных t, он может затем сделать этот новый тип экземпляром Eq, предоставив функцию равенства значений типа tлюбым удобным для него способом. Сделав это, они могут использовать функцию elemon [t], то есть списки элементов типа t.

Обратите внимание, что классы типов отличаются от классов объектно-ориентированных языков программирования. В частности, Eqэто не тип: не существует такого понятия, как значение типа Eq.

Классы типов тесно связаны с параметрическим полиморфизмом. Например, обратите внимание, что тип, elemуказанный выше, был бы параметрически полиморфным типом, a -> [a] -> Boolесли бы не ограничение класса типа " Eq a =>".

Полиморфизм высшего рода

Класс типа не обязательно должен принимать переменную типа определенного типа Type , но может принимать переменную любого типа. Эти классы типов с более высокими видами иногда называются классами-конструкторами (конструкторы, о которых идет речь, являются конструкторами типов, такими как Maybe, а не конструкторами данных, такими как Just). Примером является Monadкласс:

класс Monad m , где return :: a -> m a ( >>= ) :: m a -> ( a -> m b ) -> m b                     

Тот факт, что m применяется к переменной типа, указывает на то, что она имеет вид Type -> Type, т. е. она принимает тип и возвращает тип, вид Monadтаким образом:

Монада :: ( Тип -> Тип ) -> Ограничение      

Классы типов с несколькими параметрами

Классы типов допускают несколько параметров типа, поэтому классы типов можно рассматривать как отношения к типам. [6] Например, в стандартной библиотеке GHC класс IArrayвыражает общий интерфейс неизменяемого массива. В этом классе ограничение класса типа IArray a eозначает, что aэто тип массива, содержащий элементы типа e. (Это ограничение на полиморфизм используется, например, для реализации неупакованных типов массивов.)

Как и мультиметоды , классы типов с несколькими параметрами поддерживают вызов различных реализаций метода в зависимости от типов нескольких аргументов и даже типов возвращаемых значений. Классы типов с несколькими параметрами не требуют поиска метода для каждого вызова во время выполнения; [7] : минута 25:12,  скорее, вызываемый метод сначала компилируется и сохраняется в словаре экземпляра класса типа, как и в случае с классами типов с одним параметром.

Код Haskell, использующий классы типов с несколькими параметрами, не является переносимым, поскольку эта функция не является частью стандарта Haskell 98. Популярные реализации Haskell, GHC и Hugs , поддерживают классы типов с несколькими параметрами.

Функциональные зависимости

В Haskell классы типов были усовершенствованы, чтобы позволить программисту объявлять функциональные зависимости между параметрами типа — концепция, вдохновленная теорией реляционных баз данных . [8] [9] То есть программист может утверждать, что данное присвоение некоторого подмножества параметров типа однозначно определяет остальные параметры типа. Например, общая монада m , которая несет параметр состояния типа, sудовлетворяет ограничению класса типа Monad.State s m. В этом ограничении существует функциональная зависимость m -> s. Это означает, что для данной монады mтипа class Monad.Stateтип состояния, доступный из m, определен однозначно. Это помогает компилятору в выводе типа , а также помогает программисту в типизированном программировании.

Саймон Пейтон-Джонс возражал против введения функциональных зависимостей в Haskell по причине сложности. [10]

Классы типов и неявные параметры

Классы типов и неявные параметры очень похожи по своей природе, хотя и не совсем одинаковы. Полиморфная функция с ограничением класса типа, например:

сумма :: Num a => [ a ] ​​-> a       

можно интуитивно рассматривать как функцию, которая неявно принимает экземпляр Num:

sum_ :: Num_ a -> [ a ] ​​-> a       

По сути , экземпляр Num_ aпредставляет собой запись, содержащую определение экземпляра Num a. (Фактически именно так классы типов реализуются под капотом компилятора Glasgow Haskell.)

Однако есть важное отличие: неявные параметры более гибкие — вы можете передавать разные экземпляры Num Int. Напротив, классы типов реализуют так называемое свойство согласованности , которое требует, чтобы для любого данного типа был только один уникальный выбор экземпляра. Свойство когерентности делает классы типов несколько антимодульными, поэтому настоятельно не рекомендуется использовать потерянные экземпляры (экземпляры, определенные в модуле, который не содержит ни класс, ни интересующий тип). С другой стороны, согласованность добавляет языку дополнительный уровень безопасности, давая программисту гарантию того, что две непересекающиеся части одного и того же кода будут использовать один и тот же экземпляр. [11]

Например, для функционирования упорядоченного набора (типа Set a) требуется полный порядок элементов (типа ). aОб этом может свидетельствовать ограничение Ord a, которое определяет оператор сравнения элементов. Однако существует множество способов навести полный порядок. Поскольку алгоритмы множеств обычно нетерпимы к изменениям порядка после создания набора, передача несовместимого экземпляра функциям, Ord aкоторые работают с набором, может привести к неверным результатам (или сбоям). Таким образом, обеспечение согласованности Ord aв этом конкретном сценарии имеет решающее значение.

Экземпляры (или «словари») в классах типов Scala — это просто обычные значения языка, а не совершенно отдельный вид сущностей. [12] [13] Хотя эти экземпляры по умолчанию предоставляются путем поиска соответствующих экземпляров в области видимости, которые будут использоваться в качестве неявных фактических параметров для явно объявленных неявных формальных параметров, тот факт, что они являются обычными значениями, означает, что они могут быть предоставлены явно, разрешить двусмысленность. В результате классы типов Scala не удовлетворяют свойству связности и фактически являются синтаксическим сахаром для неявных параметров.

Это пример из документации Cats [14] :

// Класс типа для текстового представления типажа Show [ A ] { def show ( f : A ): String }      // Полиморфная функция, которая работает только при наличии // неявного экземпляра Show[A] def log [ A ]( a : A )( неявное s : Show [ A ]) = println ( s . show ( a ) )      // Экземпляр для String неявное val stringShow = new Show [ String ] { def show ( s : String ) = s }           // Параметр stringShow был вставлен компилятором. scala > log ( «строка » ) строка  

Coq (версия 8.2 и более поздние) также поддерживает классы типов, выводя соответствующие экземпляры. [15] Последние версии Agda 2 также предоставляют аналогичную функцию, называемую «аргументами экземпляра». [16]

Другие подходы к перегрузке операторов

В Standard ML механизм «типов равенства» примерно соответствует встроенному классу типов Haskell Eq, но все операторы равенства выводятся компилятором автоматически. Программистский контроль над процессом ограничивается указанием того, какие компоненты типов в структуре являются типами равенства, а переменные каких типов в диапазоне полиморфных типов превышают типы равенства.

Модули и функторы SML и OCaml могут играть роль, аналогичную роли классов типов Haskell, причем принципиальным отличием является роль вывода типа, что делает классы типов пригодными для специального полиморфизма. [17] Объектно-ориентированное подмножество OCaml — это еще один подход, который в некоторой степени сравним с подходом к классам типов.

Связанные понятия

Аналогичным понятием для перегруженных данных (реализованным в GHC ) является семейство типов . [18]

В C++, в частности, в C++20 имеется поддержка классов типов с использованием Concepts (C++) . В качестве иллюстрации приведенный выше пример класса типов Eq на Haskell можно записать как

шаблон < имя типа T > концепция Equal = требует ( T a , T b ) { { a == b } -> std :: Convertible_to < bool > ; { a != b } -> std :: Convertible_to < bool > ; };                        

Классы типов в Clean похожи на Haskell, но имеют немного другой синтаксис.

Rust поддерживает типажи , которые представляют собой ограниченную форму согласованных классов типов. [19]

В Mercury есть классы типов, хотя они не совсем такие, как в Haskell. [ нужны дальнейшие объяснения ]

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

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

Смотрите также

Рекомендации

  1. ^ Моррис, Джон Г. (2013). Классы типов и цепочки экземпляров: реляционный подход (PDF) (доктор философии). Департамент компьютерных наук Портлендского государственного университета. дои : 10.15760/etd.1010.
  2. ^ Аб Вадлер, П.; Блотт, С. (1989). «Как сделать специальный полиморфизм менее специальным». Материалы 16-го симпозиума ACM SIGPLAN-SIGACT по принципам языков программирования (POPL '89) . Ассоциация вычислительной техники. стр. 60–76. дои : 10.1145/75277.75283. ISBN 0897912942. S2CID  15327197.
  3. ^ Каес, Стефан (март 1988 г.). «Параметрическая перегрузка в полиморфных языках программирования». Учеб. 2-й Европейский симпозиум по языкам программирования . дои : 10.1007/3-540-19027-9_9 .
  4. ^ Аппель, AW; МакКуин, Д.Б. (1991). «Стандартный ML Нью-Джерси». В Малушиньском, Дж.; Вирсинг, М. (ред.). Реализация языка программирования и логическое программирование. ПЛИЛП 1991 . Конспекты лекций по информатике. Том. 528. Спрингер. стр. 1–13. CiteSeerX 10.1.1.55.9444 . дои : 10.1007/3-540-54444-5_83. ISBN  3-540-54444-5.
  5. ^ Тип from Data.Kindпоявился в версии 8 компилятора Glasgow Haskell.
  6. ^ Страница Haskell MultiParamTypeClasses .
  7. ^ В GHC ядро ​​C использует сигнатуры типов System F Girard & Reynold для идентификации типизированного случая для обработки на этапах оптимизации. -- Саймон Пейтон-Джонс «Into the Core — сжатие Haskell в девять конструкторов», Конференция пользователей Erlang, 14 сентября 2016 г.
  8. ^ Джонс, Марк П. (2000). «Классы типов с функциональными зависимостями». В Смолке Г. (ред.). Языки и системы программирования. ЭСОП 2000 . Конспекты лекций по информатике. Том. 1782. Спрингер. стр. 230–244. CiteSeerX 10.1.1.26.7153 . дои : 10.1007/3-540-46425-5_15. ISBN  3-540-46425-5.
  9. ^ Страница Haskell FunctionalDependities .
  10. ^ Пейтон-Джонс, Саймон (2006). «MPTC и функциональные зависимости». Список рассылки Haskell-prime .
  11. ^ Кметт, Эдвард. Типовые классы против мира. Бостонская встреча Haskell. Архивировано из оригинала 21 декабря 2021 г.
  12. ^ Оливейра, Бруно CdS; Мавр, Адриан; Одерский, Мартин (2010). «Классы типов как объекты и неявные выражения» (PDF) . Материалы Международной конференции ACM по языкам и приложениям объектно-ориентированных систем программирования (OOPSLA '10) . Ассоциация вычислительной техники. стр. 341–360. CiteSeerX 10.1.1.205.2737 . дои : 10.1145/1869459.1869489. ISBN  9781450302036. S2CID  207183083.
  13. ^ «Руководство для неофитов по Scala, часть 12: Классы типов - Дэниел Вестхайде» .
  14. ^ typelevel.org, Scala Cats
  15. ^ Кастеран, П.; Созо, М. (2014). «Нежное введение в классы типов и отношения в Coq» (PDF) . CiteSeerX 10.1.1.422.8091 . 
  16. ^ «Моделирование классов типов с аргументами экземпляра».
  17. ^ Дрейер, Дерек; Харпер, Роберт; Чакраварти, Мануэль М.Т. (2007). «Классы модульных типов». Материалы 34-го ежегодного симпозиума ACM SIGPLAN-SIGACT по принципам языков программирования (POPL '07). стр. 63–70. См. стр. 63. дои : 10.1145/1190216.1190229. ISBN 978-1595935755. S2CID  1828213. ТР-2006-03.
  18. ^ "Семейства GHC/Type - HaskellWiki" .
  19. ^ Турон, Аарон (2017). «Специализация, согласованность и эволюция API».

Внешние ссылки