2015-01-04 2 views
16

При изучении функторов в Haskell я придумал тип функтора Functor.Indexed. Этот функтор определяет операцию, называемую imap. Я не понял его определения и imap подпись: imap :: (a -> b) -> f j k a -> f j k b. Я попытался найти его формальное определение и нашел только следующее: http://ncatlab.org/nlab/show/indexed+functor. Но мне это действительно не помогло. Так может кто-то прояснить в более простых словах этот тип функтора и в каких случаях я должен его использовать? Благодарю.Что такое индексированный функтор в Haskell и каковы его обычаи?

+5

У меня такое ощущение, что мотивация индексированных функторов можно понять, только взглянув на индексированных _applicative_ функторов или индексированных монад. Это точно так же, как и их неиндексированные части, за исключением того, что типу (по его индексу) разрешено изменять при использовании '<*>' или '>> ='. Поэтому индекс может быть использован, например, чтобы отслеживать, сколько побочных эффектов у вас есть: 'allocSomeData :: M Zero One T1' и' allocSomeOtherData :: M One Two T2' then 'do d1 <- allocSomeData; d2 <- allocSomeOtherData; return (d1, d2) :: M Zero Two (T1, T2) 'и двойное выделение отражается в типе. – chi

ответ

18

Индексированным функтором является использование формулировки spacesuitburritoesque, «контейнер, который также содержит отображение». То есть значение f j k a будет «содержать» своего рода морфизм (не обязательно функции, могут быть более общие стрелки), а также значения типа 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' 
+1

Если я правильно понял, это должно быть 'runIxState :: i -> (a, j)', не так ли? И спасибо за это действительно хорошее объяснение, теперь они, наконец, имеют смысл для меня ... – phg

+0

Великое понятие «одновременно составляет морфизмы» –

Смежные вопросы