Для чего используется Представляемый в Haskell? - PullRequest
0 голосов
/ 19 января 2019

Я хочу понять, что означает Представляемый в Haskell. Определение

Представимые эндофункторы над категорией типов Хаскелла изоморфны монаде читателя и поэтому наследуют очень большое количество свойств бесплатно.

не достаточно ясно для меня. Я хотел бы взглянуть на реальный пример, чтобы понять, как я могу использовать tabulate и index методы.

Итак, мой вопрос:

  • Для чего используется Представляемое?
  • Не могли бы вы уточнить определение и привести пример?

1 Ответ

0 голосов
/ 19 января 2019

Representable s являются функторами, подобными содержателю, которые имеют «особые отношения» с другим типом, который служит индексом для Representable. В определении Haskell этот тип индекса задается семейством связанных типов type Rep f :: *

Для каждого значения индекса и для каждого значения Representable, мы можем вызвать функцию index :: f a -> Rep f -> a, чтобы получить соответствующий элемент. И tabulate :: (Rep f -> a) -> f a создает контейнер, в котором каждый элемент получен из своего собственного индекса.

Теперь, вот пример функтора, который НЕ ПРЕДСТАВЛЯЕМ: типичный тип списка Haskell []. Можно наивно думать, что он может быть проиндексирован чем-то вроде Natural, но проблема в том, что списки могут быть пустыми или не иметь достаточного количества элементов для достижения заданного индекса.

Всегда бесконечный тип, такой как data Stream a = Stream a (Stream a) , равен Representable, и он проиндексирован на Natural, потому что всегда будет значение для любого данного Natural, который мы передаем index .

Аналогично, однородная пара data Pair a = Pair a a индексируется типом Bool: индекс сообщает нам, какой из компонентов выбрать.

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


Чтение различных экземпляров, определенных для Representable, поучительно, но, похоже, нам нужно перейти к исходному коду, потому что связанные типы не видны в пикше. Некоторые интересные лакомые кусочки:

  • Функтор Identity индексируется по типу блока (), это имеет смысл, потому что Identity имеет, так сказать, только один «слот», поэтому нам не нужно предоставлять какую-либо информацию.

  • Тип "functions from some type" ((->) e) индексируется самим типом источника. И index это просто id. Это то, что подразумевается под «изоморфной монаде читателя», потому что Reader e - это просто новый тип по сравнению с ((->) e).

  • Composition (вложение) двух представимых функторов снова равно Representable, и оно индексируется парой исходных индексов! Это имеет смысл: сначала мы должны знать, как индексировать во внешний функтор, а затем во внутренний.

  • Product (спаривание) двух Representable функторов индексируется суммой (Either) исходных индексов. Ветвь Either сообщает нам, какую часть продукта нужно индексировать.

  • Заметное упущение (поскольку в общем случае оно неверно): (Representable f, Representable g) => Representable (Sum f g) экземпляра не существует.

...