具有多个相同变压器的monad堆栈

时间:2019-01-11 19:42:35

标签: haskell monads monad-transformers

我试图编写自己的monad转换器,在堆栈中具有多个不同类型的同一个monad转换器是有意义的。这个问题可以用读者monad来说明。

提供阅读器monad是一种保存给定类型的只读上下文的方法

ex1 :: Reader Bool Bool
ex1 = ask

ex2 :: Reader Char Bool
ex2 = pure True

monad变压器允许对下划线monad进行较少限制的假设

ex3 :: (MonadReader Bool m) => m Bool
ex3 = ask

但是,如果我想拥有多个只读环境,该怎么办?

ex4 :: (MonadReader Bool m, MonadReader Char m) => m Bool
ex4 = ask

据我所知,自

以来,没有办法运行ex4。
class Monad m => MonadReader r m | m -> r 

表示每个MonadReader都有唯一的阅读类型。在同一堆栈上是否存在针对多个跨单体的标准解决方法?我应该尝试完全避免这种情况吗?

2 个答案:

答案 0 :(得分:2)

以一种相对简单的方式处理它的方法是创建一个表示要跟踪状态的类型。假设您要像示例中那样同时跟踪布尔和字符

let services = [{
    _id: 0,
    name: "initiating"
  },
  {
    _id: 1,
    name: "evaluating"
  },
  {
    _id: 2,
    name: "servicing"
  },
]

let selected = services.findIndex(service => service.name == "evaluating")
console.log(selected)

其他人可能有更高级的解决方案!

答案 1 :(得分:2)

使用变压器抬起您的内心单子:

import Control.Monad.Trans.Reader
import Control.Monad.Trans.Class (lift)

type MyMonad a = ReaderT Bool (Reader Char) a

askBool :: MyMonad Bool
askBool = ask
askChar :: MyMonad Char
askChar = lift ask

您提供的代码未使用任何monad转换器(直接)。它使用了阅读器monad(恰好是应用于标识monad的转换器)和MonadReader类型类。正如您所注意到的,对于同一输入(monad m),MonadReader隐含的类型函数不能导致两个不同的输出(环境类型)。