如何声明两种类型的组合是一个 monad

Jul*_*rch 2 haskell

我有功能:

step :: forall m . (MonadState IntCodeState m) => m (Maybe ())
Run Code Online (Sandbox Code Playgroud)

当我do在函数体中使用符号时,它m用作 monad。正如您所料,我实际上希望它使用m Maybe. 但是,它不明白这m Maybe是一个单子。我如何向 Haskell 表达这一点?

编辑:目前这可能有点格式错误。具体类型应该是 StateT IntCodeState Maybe (),但我试图不声明具体类型,所以问题是:我该如何声明?

编辑 2:另一个尝试:我有一些看起来像这样的函数:

getValueIndex :: (MonadState IntCodeState m) => Int -> m (Maybe Int)
Run Code Online (Sandbox Code Playgroud)

在这里,我正在研究 state monad 的级别。但是,我现在希望能够“好像”m Maybe是 monad。我希望这很简单,但我想不出一种表达方式。我想写的代码是这样的

step :: forall m . (MonadState IntCodeState m) => m (Maybe ())
step = do
    full <- opCode
    let len = length (snd full) + 1
    process full <* (next += len)
Run Code Online (Sandbox Code Playgroud)

但是 opCode 返回一个m (Maybe a),我想full成为一个a

Kot*_*lar 5

但是 opCode 返回一个m (Maybe a),我想full成为一个a

看起来您想使用引擎盖下的MaybeT monad 转换器m (Maybe a)Monad实例可以满足您的需求:

MaybeT monad 转换器扩展了 monad,使其能够在不返回值的情况下退出计算。

只有当序列中的所有动作都执行时,动作序列才会产生值。如果退出,则跳过序列的其余部分并退出复合动作。

以下是类型:

MaybeT :: m (Maybe a) -> MaybeT m a

runMaybeT :: MaybeT m a -> m (Maybe a)
Run Code Online (Sandbox Code Playgroud)

这也将很有帮助,专门来自MonadTrans

lift :: m a -> MaybeT m a 
Run Code Online (Sandbox Code Playgroud)

所以在你的情况下:

step :: forall m . (MonadState IntCodeState m) => m (Maybe ())
step = runMaybeT $ do
    full <- MaybeT opCode -- :: MaybeT opCode :: MaybeT m a, full :: a
    let len = length (snd full) + 1
    lift $ process full <* (next += len)
Run Code Online (Sandbox Code Playgroud)

我假设process返回 anm ()并用于lift将其更改为MaybeT m ().