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)
экземпляра не существует.