我想将类似于 ExceptT a (StateT A M)
的东西,对于某个具体类型 A
和 monad M
,封装成我的新自定义 monad。
首先我确定 StateT A M
在其他情况下经常出现,因此我决定最好单独用一个 monad M1
将其封装起来,然后再将 ExceptT a M1
封装进 M2
中。
期望的属性是让 M1
和 M2
成为 MonadState
类的实例以及 M
的类(假设它被称为 MyMonadClass
)的实例。此外,M2
应该是 MonadError
的实例。
首先,我从简单的类型同义词开始:
type MyState = StateT A M
type MyBranch a = ExceptT a MyState
然后我想首先勾勒出实例声明(不实现实例),这就是我第一次卡住的地方。 instance MonadState A (MyState)
似乎不是正确的语法。 我想我必须创建 newtype MyState' a = StateT a M
,然后 type MyState = MyState A
(在不必要使用语言扩展的情况下)。
然而,一旦我开始将同义词转换为 newtype
声明,我开始失去与 StateT A M
和 ExceptT ...
类型的联系。
newtype MyState' s a = MyState' { runMyState :: s -> (s, a) }
type MyState = MyState' A
newtype MyBranch e a = MyBranch { runMyBranch :: MyState (Either e a) }
现在已经实现的变压器消失了,我认为我正在尝试做一些没有太多意义的事情。因此,我的问题是:如何正确地将这种行为包装成新的复合单子,使得底层可以访问,从而避免不必要的提升并保持清晰和组织良好。
GeneralizedNewtypeDeriving
? - jakubdaniel:set -ddump-deriv
,它会显示 GHC 为您编写的所有代码。data AB = A | B deriving Eq
转储instance GHC.Classes.Eq Ghci5.AB where (GHC.Classes.==) Ghci5.A Ghci5.A = GHC.Types.True; (GHC.Classes.==) Ghci5.B Ghci5.B = GHC.Types.True; (GHC.Classes.==) _ _ = GHC.Types.False
- Iceland_jack