2016-01-17 10 views
12

Können wir diese Gleichung für X lösen?Applicative ist zu monad, was X zu comonad ist

Applicative ist zu Monade, was X

+3

'ComonadApply ist zu Comonad wie Applicativ zu Monad.' http://hackage.haskell.org/package/comonad-4.2.7.2/docs/Control-Comonad.html#t:ComonadApply Es scheint nicht ganz anders als Applicative ... – danidiaz

+1

klingt wie eine Antwort! – nicolas

+3

@danidiaz Ich sehe, dass eine 'ComonadApply' eine' Comonad' sein muss - im Gegensatz zu 'Applicative', die nicht' Monad's sein müssen. Das sieht für mich als Hauptunterschied aus. – chi

Antwort

5

Nach einigem Überlegen comonad ist, denke ich, das ist eigentlich eine Rückwärts Frage. Man könnte meinen, dass ComonadApply zu Comonad gehört, was Applicative zu Monad ist, aber das ist nicht der Fall. Aber um dies zu sehen, lassen Sie uns PURESCRIPT der Hierarchie typeclass verwenden:

class Functor f where 
    fmap :: (a -> b) -> f a -> f b 

class Functor f => Apply f where 
    apply :: f (a -> b) -> f a -> f b -- (<*>) 

class Apply f => Applicative f where 
    pure :: a -> f a 

class Applicative m => Monad m where 
    bind :: m a -> (a -> m b) -> m b -- (>>=) 
-- join :: m (m a) -> m a 
-- join = flip bind id 

Wie Sie sehen können, ComonadApply ist lediglich (Apply w, Comonad w) => w. Allerdings ist Applicative die Fähigkeit, Werte in den Funktor mit pure zu injizieren, der wirkliche Unterschied.

Die Definition eines Comonad als kategorische Dual besteht aus return 's Dual extract und bind' s Dual extend (oder die alternative definiton über duplicate als join ‚s dual):

class Functor w => Comonad w where 
    extract :: w a -> a   
    extend :: (w a -> b) -> w a -> w b 
-- extend f = fmap f . duplicate k 
-- duplicate :: w a -> w (w a) 
-- duplicate = extend id 

Also, wenn wir Blick auf den Schritt von Applicative zu Monad wäre der logische Schritt zwischen einem typeclass sein mit pure ‚s dual:

class Apply w => Extract w where 
    extract :: w a -> a 

class Extract w => Comonad w where 
    extend :: (w a -> b) -> w a -> w b 

Beachten Sie, dass wir nicht extract in Bezug auf extend oder duplicate definieren können, und weder können wir pure/return in Bezug auf bind oder join definieren, so erscheint dies wie der „logische“ Schritt. apply ist hier meistens irrelevant; es kann entweder für Extract oder Monad definiert werden, solange ihre Gesetze halten:

applyC f = fmap $ extract f -- Comonad variant; needs only Extract actually (*) 
applyM f = bind f . flip fmap -- Monad variant; we need join or bind 

So Extract (Werte Aussteigen) zu Comonad ist, was Applicative (immer Werte in) zu Monad ist. Apply ist mehr oder weniger ein glücklicher kleiner Unfall auf dem Weg. Es wäre interessant, ob es in Hask Typen gibt, die Extract haben, aber nicht Comonad (oder Extend, aber nicht Comonad, siehe unten), aber ich denke, das sind eher selten.

Beachten Sie, dass Extract nicht existiert — noch. Aber auch nicht Applicative in der 2010 report. Auch, dass jeder Typ ist sowohl eine Instanz von Extract und Applicative automatisch sowohl ein Monad und ein Comonad, da Sie bind und extend in Bezug auf extract und pure definieren:

bindC :: Extract w => w a -> (a -> w b) -> w b 
bindC k f = f $ extract k 

extendM :: Applicative w => (w a -> b) -> w a -> w b 
extendM f k = pure $ f k  

* In der Lage zu definieren apply in Bezug auf extract ist ein Zeichen, dass class Extend w => Comonad w könnte mehr machbar sein, aber könnte man Monad in class (Applicative f, Bind f) => Monad f und damit Comonad in (Extend w, Extract w) => Comonad w geteilt haben, so ist es mehr oder weniger Haarspaltung.