2015-01-04 18 views
16

Beim Studieren von Funktoren in Haskell kam ich mit Functor.Indexed Art von Funktor. Dieser Funktor definiert eine Operation namens imap. Ich habe seine Definition nicht verstanden und imap Signatur: imap :: (a -> b) -> f j k a -> f j k b. Ich habe versucht, es formale Definition zu finden und fand nur dieses: http://ncatlab.org/nlab/show/indexed+functor. Aber es hat mir wirklich nicht geholfen. Kann also jemand in einfacheren Worten diese Art von Funktor erklären und in welchen Fällen sollte ich ihn benutzen? Vielen Dank.Was ist genau ein indizierter Funktor in Haskell und was sind seine Verwendungen?

+5

Mein Gefühl ist, dass die Motivation hinter indizierte functors nur durch einen Blick auf indizierte _applicative_ functors verstanden werden kann, oder indiziert Monaden. Diese sind genau wie ihre nicht indizierten Teile, außer dass der Typ (in seinem Index) sich ändern kann, wenn '<*>' oder '>> =' verwendet wird. Der Index kann daher z.B. um zu verfolgen, wie viele Nebenwirkungen Sie haben: 'allocSomeData :: M Zero One T1' und' allocSomeOtherData :: M One Two T2' dann 'do d1 <- allocSomeData; d2 <- allocSomeOtherData; return (d1, d2) :: M Zero Two (T1, T2) 'und die Doppelbelegung spiegelt sich im Typ wider. – chi

Antwort

18

Ein indizierter Funktor ist, zu verwenden spacesuitburritoesque Formulierung, "ein Container, der auch eine Zuordnung enthält". I.e. ein Wert f j k a wird irgendeine Art von Morphismus (en) enthalten j -> k(nicht notwendigerweise funktioniert, können allgemeinere Pfeile sein) und auch Werte vom Typ a.

Für die a Werte ist der Container ein Funktor in der offensichtlichen Weise. In der Tat die IxFunctor Klasse für sich ist ziemlich langweilig - ein

instance IxFunctor f 

ist grundsätzlich die gleiche wie

instance Functor (f j k) 

Jetzt, wo es interessant wird, wenn man die spezifischeren Funktors Klassen berücksichtigen. Diese Monade man nicht wirklich im Indexed Modul ist, aber ich denke, es ist der Punkt am besten klar macht:

class IxPointed f => IxMonad f where 
    ijoin :: m j k (m k l a) -> m j l a 

vergleichen Sie diese Seite an Seite:

(>>>) :: (j->k) -> (k->l) -> j->l 
ijoin :: m j k (m k l a) -> m j l a 
join :: m  (m  a) -> m  a 

Also, was wir tun, ist, während wir die "container-layers" verbinden, bilden wir die Morphismen.

Das offensichtliche Beispiel ist IxState. Rufen Sie den Standardzustand Monade

newtype State s a = State { runState :: s -> (a, s) } 

Dies, wenn sie als Monade verwendet, einfach komponiert die s -> s Aspekt der Funktion:

join (State f) = State $ \s -> let (State f', s') = f s in f' s' 

, so dass Sie den Zustand Faden zunächst durch f, dann durch f'. Nun, es gibt wirklich keinen Grund, warum wir alle Staaten brauchen, um den gleichen Typ zu haben, oder? Immerhin wird der Zwischenzustand lediglich an die nächste Aktion weitergegeben. Hier ist der indexierten Zustand Monade,

newtype IxState i j a = IxState { runIxState :: i -> (a, j) } 

Es tut genau das:

ijoin (IxState f) = IxState $ \s -> let (IxState f', s') = f s in f' s' 
+1

Wenn ich das richtig verstanden habe, sollte es 'runIxState :: i -> (a, j)' sein, oder? Und danke für diese wirklich gute Erklärung, jetzt machen diese endlich Sinn für mich ... – phg

+0

Große Vorstellung von "komponiert gleichzeitig Morphismen" –