整理Monads - 将monad变换器的应用转变为新型monad [英] Tidying up Monads - turning application of a monad transformer into newtype monad
问题描述
ExceptT(StateT AM)
,对于某些具体类型 A
和monad M
,并将它们包装到我的新自定义monads中。首先我确定出现 StateT AM
通常在其他上下文中,因此我决定最好将它单独包装在单元 M1
中,然后包装 ExceptT a M1
到 M2
。
所需的属性是使 M1
和 M2
MonadState
的实例和 M $ c $的类(让我们假设它被称为
MyMonadClass
)。 M2
应该是 MonadError
的一个实例。
首先我从简单类型同义词开始:
type MyState = StateT AM
类型MyBranch a =除了MyState
然后我想我会首先勾画实例声明(不实现实例)并且这是我第一次得到的卡住。 然而,一旦我开始将同义词转换为 现在已经实施的变形金刚消失了,我想我正在尝试做一些没有多大意义的事情。所以我的问题是:如何正确地将这种行为包装到新的复合monad中,以便访问下面的图层,以避免不必要的提升,并保持事情清晰和组织良好。 正常模式是为您的整个变压器堆栈定义一个新类型。 如果堆栈中有任何部分自行添加有意义的新功能,您还需要为这些部分定义新类型。 然后使用 您必须亲自编写 如果有任何堆栈增加了有意义的新功能 您通常还会为 I am trying to take e.g. First I identified that The desired property is to make First I started by simple type synonyms: then I thought that I would first sketch the instance declarations (without implementing the instance) and thats where I first got stuck. However once I started converting the synonyms into Now the transformers that are already implemented disappeared and I think I am trying to do something that does not make much sense. So my question is: How would one correctly wrap this kind of behaviour into new compound monads that make accessible the layers underneath so that one avoids unnecessary lifting and keeps things clear and well-organized. The normal pattern is to define a newtype for your complete transformer stack. If there are any pieces of the stack that add meaningful new capabilities on their own you'd also define newtypes for those pieces. Then you use You'll have to write the If there are any pieces of the stack that add meaningful new capabilities You'll also usually make a type synonym for
这篇关于整理Monads - 将monad变换器的应用转变为新型monad的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!实例MonadState A(MyState)
似乎不是正确的语法。我想我必须创建 newtype MyState'a = StateT a M
,然后
newtype
声明,我开始失去与 StateT AM
和 ExceptT ...
类型的连接。
newtype MyState'sa = MyState'{runMyState :: s - > (s,a)}
type MyState = MyState'A
newtype MyBranch ea = MyBranch {runMyBranch :: MyState(ea)}
data A = A
data E = E
newtype MyBranchT ma = MyBranchT {getMyBranchT :: ExceptT E(StateT a m)a}
$ b GeneralizedNewtypeDeriving
来获取所有monad类的实例。
{ - #LANGUAGE GeneralizedNewtypeDeriving# - }
- base
import Control.Applicative
import Control.Monad
- 变形金刚
导入Control.Monad.IO.Class
导入Control.Monad.Trans.Class
导入Control.Monad.Trans.Except
导入Control.Monad.Trans.State.Lazy
- mtl类
导入Control.Monad.Cont.Class
导入Control.Monad.Error.Class
导入Control.Monad.Reader.Class
导入Control.Monad.State.Class
import Control.Monad.Writer.Class
data A = A
data E = E
newtype MyBranchT ma = MyBranchT {getMyBranchT :: ExceptT E( StateT a m)a}
派生(Functor,Applicative,Monad,MonadIO, - 基类和变换器的类
{ - Alternative,MonadPlus, - } - 如果E是幺半群
MonadState A,MonadError E, - MyBranchT提供的来自mtl的类
MonadCont,MonadReader r,MonadWriter w) - 可能从m
MonadTrans
实例。 lift
永远只是 lift
为堆栈中的每个转换器添加一次。
实例MonadTrans MyBranchT其中
lift = MyBranchT。电梯 。提升
X
你自己也可以为这些功能定义一个新的 MonadX
类,编写 MonadX
StateT , ExceptT
, ContT $ c> $ c>等),并为你的变量栈(
MyBranchT
)派生 MonadX
实例。 p>
MyBranchT Identity
和 runMyBranchT
和
runMyBranch
import Data.Functor.Identity
类型MyBranch a = MyBranchT标识a
runMyBranchT :: MyBranchT ma - > A - > m(E a,A)
runMyBranchT mb s = runStateT(runExceptT(getMyBranchT mb))s
runMyBranch :: MyBranch a - > A - > (E a,A)
runMyBranch mb s = runIdentity $ runMyBranchT mb s
ExceptT a (StateT A M)
, for some concrete type A
and monad M
, and wrap them up into my new custom monads.StateT A M
appears often in other contexts and thus I decided it would be best to wrap that alone in a monad M1
and then wrap ExceptT a M1
into M2
.M1
and M2
instances of MonadState
and the class of M
(lets assume it is called MyMonadClass
). Also M2
should be an instance of MonadError
.type MyState = StateT A M
type MyBranch a = ExceptT a MyState
instance MonadState A (MyState)
seemed to not be the right syntax. I thought I would have to create newtype MyState' a = StateT a M
and then type MyState = MyState A
(Lets not use language extensions where not necessary).newtype
declarations I started to lose the connection to the StateT A M
and ExceptT ...
types.newtype MyState' s a = MyState' { runMyState :: s -> (s, a) }
type MyState = MyState' A
newtype MyBranch e a = MyBranch { runMyBranch :: MyState (Either e a) }
data A = A
data E = E
newtype MyBranchT m a = MyBranchT { getMyBranchT :: ExceptT E (StateT A m) a }
GeneralizedNewtypeDeriving
to get instances for all of the various monad classes.{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-- base
import Control.Applicative
import Control.Monad
-- transformers
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Control.Monad.Trans.Except
import Control.Monad.Trans.State.Lazy
-- mtl classes
import Control.Monad.Cont.Class
import Control.Monad.Error.Class
import Control.Monad.Reader.Class
import Control.Monad.State.Class
import Control.Monad.Writer.Class
data A = A
data E = E
newtype MyBranchT m a = MyBranchT { getMyBranchT :: ExceptT E (StateT A m) a }
deriving (Functor, Applicative, Monad, MonadIO, -- classes from base and transformers
{- Alternative, MonadPlus, -} -- if E is a monoid
MonadState A, MonadError E, -- classes from mtl that MyBranchT provides
MonadCont, MonadReader r, MonadWriter w) -- classes from mtl that might be available from m
MonadTrans
instance by hand. lift
is always just lift
once for each of the transformers in the stack.instance MonadTrans MyBranchT where
lift = MyBranchT . lift . lift
X
on their own you'd also define a new MonadX
class for those capabilities, write MonadX
instances for each of the monad transfomers (StateT
, ExceptT
, ContT
, etc) if possible, and derive the MonadX
instance for your transformer stack (MyBranchT
).MyBranchT Identity
and functions to runMyBranchT
and runMyBranch
import Data.Functor.Identity
type MyBranch a = MyBranchT Identity a
runMyBranchT :: MyBranchT m a -> A -> m (Either E a, A)
runMyBranchT mb s = runStateT (runExceptT (getMyBranchT mb)) s
runMyBranch :: MyBranch a -> A -> (Either E a, A)
runMyBranch mb s = runIdentity $ runMyBranchT mb s