围绕 Streaming & Reader 构建一个 monad
Building a monad around Streaming & Reader
我正在尝试构建以下类型的 Monad
实例:
data CmdY ρ η ω = CmdY (Reader ρ ((Stream (Of CmdSpec) η ω)))
其中 Stream
和 Of
来自 streaming
包中的 Streaming
。
我已经成功编写了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) η ω)
但是给定一个 a >>= f
形式的绑定,a 是 CmdY (ProcExecCtxt η) η α
类型,而 f 是 α -> CmdY (ProcExecCtxt η) η β
类型,我需要得到一些 α 类型的东西来喂我f,我没能到达那里。
ProcExecCtxt m
这里是一个执行上下文;它提供了一种在 monad m.
中评估 cmds 的方法
我确定我遗漏了一些明显的东西(或者至少,我希望一旦我看到它就会很明显);但我很感激任何指点。
谢谢,
Data.Functor.Compose
实现了您的 Functor
和 Applicative
实例。
ReaderT
为您实现了一个 Monad
实例。
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
是一个单子变换器,所以 ReaderT e m
是一个单子,只要 m
是。因此,它将免费提供您想要的所有实例,以及更多实例。的确,使用
{-# language GeneralizedNewtypeDeriving #-}
你可以写
newtype CmdY ρ η ω = CmdY
{ unCmdY :: ReaderT ρ (Stream (Of CmdSpec) η) ω }
deriving (Functor, Applicative, Monad
, Alternative, MonadPlus, MonadReader ρ)
或者,如果您愿意,可以通过包装和解包手动定义实例 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 ρ
本身就是一个 monad 转换器:
import Control.Monad.Trans.Class
instance MonadTrans (CmdY ρ) where
lift = CmdY . lift . lift
我正在尝试构建以下类型的 Monad
实例:
data CmdY ρ η ω = CmdY (Reader ρ ((Stream (Of CmdSpec) η ω)))
其中 Stream
和 Of
来自 streaming
包中的 Streaming
。
我已经成功编写了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) η ω)
但是给定一个 a >>= f
形式的绑定,a 是 CmdY (ProcExecCtxt η) η α
类型,而 f 是 α -> CmdY (ProcExecCtxt η) η β
类型,我需要得到一些 α 类型的东西来喂我f,我没能到达那里。
ProcExecCtxt m
这里是一个执行上下文;它提供了一种在 monad m.
我确定我遗漏了一些明显的东西(或者至少,我希望一旦我看到它就会很明显);但我很感激任何指点。
谢谢,
Data.Functor.Compose
实现了您的 Functor
和 Applicative
实例。
ReaderT
为您实现了一个 Monad
实例。
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
是一个单子变换器,所以 ReaderT e m
是一个单子,只要 m
是。因此,它将免费提供您想要的所有实例,以及更多实例。的确,使用
{-# language GeneralizedNewtypeDeriving #-}
你可以写
newtype CmdY ρ η ω = CmdY
{ unCmdY :: ReaderT ρ (Stream (Of CmdSpec) η) ω }
deriving (Functor, Applicative, Monad
, Alternative, MonadPlus, MonadReader ρ)
或者,如果您愿意,可以通过包装和解包手动定义实例 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 ρ
本身就是一个 monad 转换器:
import Control.Monad.Trans.Class
instance MonadTrans (CmdY ρ) where
lift = CmdY . lift . lift