2016-11-21 5 views
6

Hier ist, wie wir KleisliFunctor definieren:Was ist das mit KleisliFunctor?

class (Monad m, Functor f) => KleisliFunctor m f where 
    kmap :: (a -> m b) -> f a -> f b 
    kmap f = kjoin . fmap f 

    kjoin :: f (m a) -> f a 
    kjoin = kmap id 

Hat diese Typklasse

class (Functor f, Monad m) => Absorb f m where 
    (>>~) :: f a -> (a -> m b) -> m b 
    a >>~ f = ajoin $ fmap f a 

    ajoin :: f (m a) -> m a 
    ajoin a = a >>~ id 

fit irgendwo in der Kategorie Theorie? Was sind die Gesetze? Sind sie

a >>~ g . f  === fmap f a >>~ g 
a >>~ (f >=> g) === a >>~ f >>= g 

?

+0

Haben Sie einen bestimmten Beispieltyp, der eine 'Absorb'-Instanz zulässt, aber keine ausreichend mächtigen Standardinstanzen zur Implementierung von '(>> ~)' und 'ajoin'? – leftaroundabout

+0

@leftaroundabout, ich brauche 'Absorb', um eine generalisierte monadische Faltung zu implementieren, die es erlaubt, einen Akkumulator im' f'-Funktor zu halten, aber das Ergebnis in der 'm'-Monade zurückgibt. Siehe z.B. [this] (https://github.com/effectify/prefolds/blob/374257b12f9a2af752862addafe456cded9c0efb/test/Main.hs#L297). – user3237465

Antwort

4

Dies ist eine spekulative Antwort. Mit Vorsicht fortfahren.

Lassen Sie uns zuerst KleisliFunctor betrachten, auf dem bind artigen Pfeil Mapping konzentriert:

class (Monad m, Functor f) => KleisliFunctor m f where 
    kmap :: (a -> m b) -> f a -> f b 

Damit dies tatsächlich ein Funktor von der Kleisli Kategorie von m zu sein Hask, kmap die relevanten folgen hat Funktors Gesetze:

-- Mapping the identity gives identity (in the other category). 
kmap return = id 
-- Mapping a composed arrow gives a composed arrow (in the other category). 
kmap (g <=< f) = kmap g . kmap f 

Die Tatsache, dass es zwei Functor s beteiligt macht die Sache ein wenig ungewöhnlich, b ut nicht unvernünftig - zum Beispiel gelten die Gesetze für mapMaybe, das ist das erste konkrete Beispiel, das der KleisliFunctor Post darauf anspielt.

Was Absorb, werde ich das bind-ähnliches Verfahren aus Gründen der Klarheit Flip:

class (Functor f, Monad m) => Absorb f m where 
    (~<<) :: (a -> m b) -> f a -> m b 

Wenn wir für etwas analog zu KleisliFunctor suchen, eine Frage, die sofort stellt, ist, welche Kategorie Funktionen haben würde vom Typ f a -> m b als Pfeile. Es kann sicherlich nicht sein Hask, da seine Identität (des Typs f a -> m a) nicht id sein kann. Wir müssten nicht nur Identität, sondern auch Zusammensetzung herausfinden. Für etwas, das nicht ganz im Gegensatz zu Monad ist ...

idAbsorb :: f a -> m a 
compAbsorb :: (f b -> m c) -> (f a -> m b) -> (f a -> m c) 

... die einzige plausible Sache, die ich Recht jetzt denken kann, ist mit einer Monade morphism als idAbsorb und unter Verwendung eines zweiten Monade morphism in der entgegengesetzten Richtung (dh ist, von m zu f), so dass compAbsorb durch Anwendung der ersten Funktion implementiert werden kann, dann zurück zu f gehen und schließlich die zweite Funktion anwenden. Wir müssten das herausfinden, um zu sehen, ob meine Annahmen angemessen sind, ob dieser Ansatz funktioniert und ob er zu etwas führt, das für Ihre Zwecke nützlich ist.

+0

"Welche Kategorie hätte Funktionen des Typs' fa -> mb' als Pfeile "- Ich weiß nichts über Pfeile, aber sind diese Objekte nicht in der Komma - Kategorie von zwei endofunctors auf' Hask': 'f' und' m'? Keine Ahnung, was es uns aber gibt.'compAbsorb' ist für mich sehr unbefriedigend: Zum einen möchte ich nicht, dass' fb-> mc' ein Monad-Morphismus ist, da mein 'f' eine eher dumme Monadeninstanz hat, für zwei mein Anwendungsfall (siehe Kommentar) (unter der Frage) muss nicht von "m" zu "f" gehen und ich will das nicht aufzwingen. Danke für die Antwort, es hat mir einiges klargemacht. – user3237465

+1

@ user3237465 Wenn Sie Ihren Code betrachten, scheint er Ihre Erwartungen zu bestätigen. Insbesondere versuchen Sie, die "offensichtliche" Sache zu machen, indem Sie "idAbsorb = slift" und "compAbsorb = g" versuchen. runDriveT. f 'fällt auf die erste Hürde -' compAbsorb idAbsorb f' ist nicht 'f' (es ändert' Stop' in 'More'), und so haben wir nicht einmal eine Kategorie. Von "DriveT m" zu "m" zu gehen, verursacht Probleme und, wie Sie sagen, macht es wenig Sinn, dies während der Komposition in Ihrem Anwendungsfall zu tun. Übrigens, beachten Sie, dass Ihr '(> ~>)' weder '(> =>)' noch 'flip compAbsorb' ist, was zu bestätigen scheint, dass Sie tatsächlich etwas anderes wollen. – duplode