我的功能类似于下面的myFunction
:
data MyError = E1 | E2
f s = if s == "" then Left E1 else Right $ reverse s
g = (fmap reverse) . f
myFunction :: String -> Either MyError (String, String)
myFunction s = do
s1 <- f s
s2 <- g s1
return (s2, s2)
所以它调用了Either
monad中的各种其他函数,所以一切正常。
现在我的情况是其中一个函数的类型,比如g
,变为
g :: CPRG r => r -> String -> (Either MyError String, r)
供参考,&#34;现实世界&#34;代码是decode
函数here,更改的函数是Jwe.rsaDecode
(我在解密函数中添加了RSA盲注)。
因此,myFunction
需要具有相同的类型,以便我可以传入CPRG
并返回它。我很难看到如何继续使用Either
monad和传递RNG这样的东西,并且仍然能够在失败和成功案例中提取RNG的最终状态,这样就可以退货了。
答案 0 :(得分:2)
类型
r -> (Either e a, r)
是monad变压器。特别是,它是ExceptT
转换器
newtype ExceptT e m a = ExceptT (m (Either e a))
我们会将其专门用于State
,以便
r -> (Either e a, r)
~
ExceptT e (State r) a
那么monad变压器是什么?好吧,事实证明,当你把两个monad放在一起并堆叠它们时,你最终会得到另一个monad。情况并非总是如此,一般来说有点棘手(与Applicative
不同,其中Applicative
仿函数的堆栈总是再次Applicative
仿函数。
也就是说,上面链接的图书馆mtl
展示了一系列常见的&#34;变形金刚&#34;它编码堆叠monad的常用方法。因此,ExceptT
是其中一个&#34;食谱&#34;并且只要ExceptT e m a
也是m
,就会设计Monad
为monad。
现在我们可以创建一个新类型别名
type M r a = ExceptT MyError (State r) a
并将g
写为类似
g' :: CPRG r => String -> M r String
g' s = do
r <- lift get -- lift "lifts" State monad computations up
let (e, r') = g r s
lift $ put r'
either throwError return e -- here we generalize an Either
-- into the M monad.