Essayer de composer le non-composable: les monades

Combien de fois avez-vous entendu ce mantra "les monades ne composent pas"? J'ai passé beaucoup de temps à essayer de réfuter cette affirmation, en essayant de résoudre le problème de front. Mais comme beaucoup de choses en mathématiques, parfois pour essayer de comprendre quelque chose, parfois il vaut la peine de changer l'échelle.





Il est recommandé de lire la première et la deuxième partie de cette série, si vous ne l'avez pas fait.





Lorsque nous voulons fusionner deux effets en un seul, c'est-à-dire les concaténer dans un transformateur, nous avons deux options: imbriquer la gauche dans la droite ou la droite dans la gauche. Ces deux options sont définies avec les schémas TU et UT :





newtype TU t u a = TU (t :. u := a)
newtype UT t u a = UT (u :. t := a)
      
      



Comme nous le savons déjà dans les parties précédentes de cette série, pour les calculs avec un environnement immuable ( Reader ), la composition directe des foncteurs est suffisante, et pour les effets de gestion des erreurs ( Peut - être et l'un ou l'autre ), un schéma avec composition inverse de UT convient .





type instance Schema (Reader e) = TU ((->) e)
type instance Schema (Either e) = UT (Either e)
type instance Schema Maybe = UT Maybe
      
      



Les instances du foncteur covariant régulier et applicatif semblent triviales, car il s'agit toujours d'un foncteur, et les foncteurs sont composés:





(<$$>) :: (Functor t, Functor u) => (a -> b) -> t :. u := a -> t :. u := b
(<$$>) = (<$>) . (<$>)

(<**>) :: (Applicative t, Applicative u) => t :. u := (a -> b) -> t :. u := a -> t :. u := b
f <**> x = (<*>) <$> f <*> x

instance (Functor t, Functor u) => Functor (TU t u) where
    fmap f (TU x) = TU $ f <$$> x

instance (Applicative t, Applicative u) => Applicative (TU t u) where
    pure = TU . pure . pure
    TU f <*> TU x = TU $ f <**> x

instance (Functor t, Functor u) => Functor (UT t u) where
    fmap f (UT x) = UT $ f <$$> x

instance (Applicative t, Applicative u) => Applicative (UT t u) where
    pure = UT . pure . pure
    UT f <*> UT x = UT $ f <**> x
      
      



Des problèmes surviennent lorsque nous essayons de décrire les monades. Il n'est pas clair comment trouver un moyen généralisé, étant donné que les deux effets nous sont inconnus:





instance (Monad t, Monad u) => Monad (TU t u) where
  x >>= f = ???

instance (Monad t, Monad u) => Monad (UT t u) where
  x >>= f = ???
      
      



, . :





instance Monad u => Monad (TU ((->) e) u) where
    TU x >>= f = TU $ \e -> x e >>= ($ e) . run . f

instance Monad u => Monad (UT (Either e) u) where
    UT x >>= f = UT $ x >>= \case
        Left e -> pure $ Left e
        Right r -> run $ f r

instance Monad u => Monad (UT Maybe u) where
    UT x >>= f = UT $ x >>= \case
        Nothing -> pure Nothing
        Just r -> run $ f r
      
      



(Maybe Either), : a, . Traversable! :





class (Functor t, Foldable t) => Traversable t where
    traverse :: Applicative f => (a -> f b) -> t a -> f (t b)

instance Traversable Maybe where
    traverse _ Nothing = pure Nothing
    traverse f (Just x) = Just <$> f x

instance Traversable (Either a) where
    traverse _ (Left x) = pure (Left x)
    traverse f (Right y) = Right <$> f y
      
      



:





instance (Traversable t, Monad t, Monad u) => Monad (UT t u) where
    UT x >>= f = UT $ x >>= \i -> join <$> traverse (run . f) i
      
      



! , Traversable .





TU, - Reader? . - - Traversable - Distributive. , Reader (, - (->) e)!





class Functor g => Distributive g where
    collect :: Functor f => (a -> g b) -> f a -> g (f b)

instance Distributive ((->) e) where
    collect f q e = flip f e <$> q
      
      



? , a -> t b , - id:





sequence :: (Traversable t, Applicative u) => t (u a) -> u (t a)
sequence = traverse id

distribute :: (Distributive t, Functor u) => u (t a) -> t (u a)
distribute = collect id
      
      



! , . Traversable , Distributive ?





instance (Monad t, Distributive t, Monad u) => Monad (TU t u) where
    TU x >>= f = TU $ x >>= \i -> join <$> collect (run . f) i
      
      



! , :





  • UT - Traversable.





  • TU - Distributive.









, State Store:





newtype TUT t t' u a = TUT (t :. u :. t' := a)

newtype State s a = State ((->) s :. (,) s := a)
newtype Store s a = Store ((,) s :. (->) s := a)

type instance Schema (State s) = TUT ((->) s) ((,) s)
type instance Schema (Store s) = TUT ((,) s) ((->) s)
      
      



, . , - , . , , , .





instance (Functor t, Functor t', Functor u) => Functor (TUT t t' u) where
    fmap f (TUT x) = TUT $ f <$$$> x
      
      



, ( (->) s) Distributive, ((,) s) - Traversable... , ( ):





class Functor t => Adjunction t u where
    leftAdjunct  :: (t a -> b) -> a -> u b
    rightAdjunct :: (a -> u b) -> t a -> b
    unit :: a -> u :. t := a
    unit = leftAdjunct id
    counit :: t :. u := a -> a
    counit = rightAdjunct id

instance Adjunction ((,) s) ((->) s) where
    leftAdjunct :: ((s, a) -> b) -> a -> (s -> b) 
    leftAdjunct f a s = f (s, a)
    rightAdjunct :: (a -> s -> b) -> (s, a) -> b
    rightAdjunct f (s, a) = f a s
    unit :: a -> s -> (s, a)
    unit x = \s -> (s, x)
    counit :: (s, (s -> a)) -> a
    counit (s, f) = f s
      
      



. State unit, , :





instance Monad (State s) where
    State x >>= f = State $ rightAdjunct (run . f) <$> x
    --  : State x >>= f = State $ counit <$> ((run . f) <$$> x)
    return = State . unit
      
      



? ((->) s) ((,) s) , . , - :





instance (Adjunction t' t, Monad u) => Monad (TUT t t' u) where
    x >>= f = TUT $ (>>= rightAdjunct (run . f)) <$> run x
    return = TUT . (leftAdjunct pure)
      
      



, , :





instance (Adjunction t' t, Comonad u) => Comonad (TUT t' t := u) where
    extend f x = TUT $ (=>> leftAdjunct (f . TUT)) <$> run x
    extract = rightAdjunct extract . run
      
      



, , ? ! , ...





instance (Adjunction t' t, Distributive t) => MonadTrans (TUT t t') where
    lift = TUT . collect (leftAdjunct id)

instance (Adjunction t' t, Applicative t, forall u . Traversable u) => ComonadTrans (TUT t' t) where
    lower = rightAdjunct (traverse id) . run
      
      



, :





  • Traversable - UT.





  • Distributive - TU.





  • (Adjunction) - TUT.





, - , .





Des sources avec des définitions peuvent être trouvées  ici . Des exemples d'utilisation du système d'effets décrit peuvent être trouvés ici .








All Articles