将状态添加到Either

时间:2014-09-08 13:37:33

标签: haskell

我的功能类似于下面的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的最终状态,这样就可以退货了。

1 个答案:

答案 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.