【发布时间】:2018-03-16 13:45:35
【问题描述】:
我对@987654321@ 中描述的用于从伴随函子确定单子变换器的构造很感兴趣。下面是一些总结基本思想的代码:
{-# LANGUAGE MultiParamTypeClasses #-}
import Control.Monad
newtype Three g f m a = Three { getThree :: g (m (f a)) }
class (Functor f, Functor g) => Adjoint f g where
counit :: f (g a) -> a
unit :: a -> g (f a)
instance (Adjoint f g, Monad m) => Monad (Three g f m) where
return = Three . fmap return . unit
m >>= f = Three $ fmap (>>= counit . fmap (getThree . f)) (getThree m)
instance (Adjoint f g, Monad m) => Applicative (Three g f m) where
pure = return
(<*>) = ap
instance (Adjoint f g, Monad m) => Functor (Three g f m) where
fmap = (<*>) . pure
鉴于Adjoint ((,) s) ((->) s),Three ((->) s) ((,) s) 看起来等同于StateT s。
非常酷,但我对一些事情感到困惑:
我们如何将一个单子
m a升级为一个单子Three g f m a?对于Three ((->) s) ((,) s)的具体情况,如何做到这一点当然很明显,但如果Adjoint f g有一个适用于任何Three g f的配方似乎是可取的。换句话说,似乎应该有一个lift的类比,其定义只需要unit、counit,以及输入monad 的return和>>=。但我似乎找不到(我见过a definition usingsequence,但这似乎有点像作弊,因为它要求f是Traversable)。就此而言,我们如何将
g a升级为Three g f m a(提供Adjoint f g)?同样,对于Three ((->) s) ((,) s)的具体情况,如何做到这一点很明显,但我想知道是否有类似的gets只需要unit、counit,以及return和>>=输入单子。
【问题讨论】:
-
注:您的
(>>=)实现可以简化为m >>= f = Three $ fmap (>>= counit . fmap (getThree . f)) (getThree m) -
我已经给这个问题写了a follow-up,这个问题最初计划在这里作为答案,但范围扩大了太多。感谢您引起我对这个话题的关注!
标签: haskell monads monad-transformers state-monad