Ответ 1
Индексированным функтором является использование spaceuitburritoesque формулировки "контейнер, который также содержит отображение". То есть значение f j k a
будет содержать "некоторый тип морфизма (s) j -> k
(не обязательно функции, могут быть более общие стрелки) а также значения типа a
.
Для этих значений a
контейнер является функтором очевидным образом. На самом деле класс IxFunctor
сам по себе довольно скучный -
instance IxFunctor f
в основном совпадает с
instance Functor (f j k)
Теперь, когда это становится интересным, вы рассматриваете более конкретные классы функторов. Эта монада на самом деле не находится в модуле Indexed
, но я думаю, что это делает точку лучше:
class IxPointed f => IxMonad f where
ijoin :: m j k (m k l a) -> m j l a
сравните это бок о бок:
(>>>) :: (j->k) -> (k->l) -> j->l
ijoin :: m j k (m k l a) -> m j l a
join :: m (m a) -> m a
Итак, что мы делаем, присоединяясь к "контейнерным слоям", мы составляем морфизмы.
Очевидным примером является IxState
. Вспомните стандартную монаду штата
newtype State s a = State { runState :: s -> (a, s) }
Это, когда используется в качестве монады, просто составляет аспект функции s -> s
:
join (State f) = State $ \s -> let (State f', s') = f s in f' s'
чтобы вы сначала передали состояние через f
, затем через f'
. Ну, действительно нет причин, по которым нам нужно, чтобы все государства имели один и тот же тип, верно? В конце концов, промежуточное состояние просто переходит к следующему действию. Здесь индексированная монада состояний,
newtype IxState i j a = IxState { runIxState :: i -> (a, j) }
Он делает именно это:
ijoin (IxState f) = IxState $ \s -> let (IxState f', s') = f s in f' s'