首页 > 解决方案 > 围绕 Streaming & Reader 构建一个 monad

问题描述

我正在尝试构建Monad以下类型的实例:

data CmdY ρ η ω = CmdY (Reader ρ ((Stream (Of CmdSpec) η ω)))

包装中的哪里StreamOf来自哪里。Streamingstreaming

我已经成功编写了Functor Applicative实例:

instance (Monad η) => Functor (CmdY ρ η) where
  fmap :: (α -> β) -> CmdY ρ η α -> CmdY ρ η β
  fmap f (CmdY a) = CmdY $ (fmap f) <$> a

instance (Monad η) => Applicative (CmdY ρ η) where
  pure    = CmdY . pure . return

  (<*>) :: CmdY ρ η (α -> β) -> CmdY ρ η α -> CmdY ρ η β
  (CmdY f) <*> (CmdY a) = let ff = (<*>) <$> f
                           in CmdY $ ff <*> a

但我正在兜圈子试图实现(>>=)Monad 的绑定。

我有一个函数来评估 CmdY 并给我一个流和结果:

runCmdY :: (MonadIO η, MonadIO μ, MonadReader (ProcExecCtxt μ) ψ) =>
           CmdY (ProcExecCtxt μ) η ω -> ψ (Stream (Of CmdSpec) η ω)

但是给定 form 的绑定a >>= f, a 是 typeCmdY (ProcExecCtxt η) η α而 f 是 type α -> CmdY (ProcExecCtxt η) η β,我需要得到一些 α 类型的东西来喂给我的 f,但我没能到达那里。

ProcExecCtxt m这是一个执行上下文;它提供了一种在 monad m 中评估 cmds 的方法。

我确定我遗漏了一些明显的东西(或者至少,我希望一旦我看到它就会很明显);但我会感谢任何指示。

谢谢,

标签: haskelltypesmonad-transformers

解决方案


Reader ρ (Stream (Of CmdSpec) η ω)

真的只是

 ρ -> Stream (Of CmdSpec) η ω

还有第三种拼写该类型的方法,在这种情况下可能更有意义:

ReaderT ρ (Stream (Of CmdSpec) η) ω

使用Control.Monad.Trans.Reader.ReaderT(也由 导出Control.Monad.Reader),定义的 monad 转换器

newtype ReaderT e m a = ReaderT
  { runReaderT :: e -> m a }

既然ReaderT e是 monad 转换器,ReaderT e m那么无论何时m都是 monad。因此,它将免费提供您想要的所有实例,以及更多。确实,使用

{-# language GeneralizedNewtypeDeriving #-}

你可以写

newtype CmdY ρ η ω = CmdY
  { unCmdY :: ReaderT ρ (Stream (Of CmdSpec) η) ω }
  deriving (Functor, Applicative, Monad
           , Alternative, MonadPlus, MonadReader ρ)

或者,如果您愿意,可以通过 wrapping 和 unwrapping 手动定义实例CmdY

instance Monad η => Functor (CmdY ρ η) where
  fmap f (CmdY m) = CmdY (fmap f m)

instance Monad η => Applicative (CmdY ρ η) where
  pure = CmdY . pure
  CmdY fs <*> CmdY xs = CmdY (fs <*> xs)

instance Monad η => Monad (CmdY ρ η) where
  CmdY m >>= f = CmdY $ m >>= unCmdY . f

CmdY ρ本身就是一个单子变压器:

import Control.Monad.Trans.Class

instance MonadTrans (CmdY ρ) where
  lift = CmdY . lift . lift

推荐阅读