围绕Streaming和Reader构建monad

时间:2018-07-19 10:31:06

标签: haskell types monad-transformers

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

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

其中StreamOf来自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是执行上下文;它提供了一种评估单子m中cmds的方法。

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

谢谢

2 个答案:

答案 0 :(得分:3)

cy.on('select', 'node', function (evt) {}

真的只是

cy.on('select', 'node', function (evt) {
    let selectedElements = cy.elements(':selected');
    let selectedIds = [];

    for (let i = 0; i < selectedElements.length; i++) {
        selectedIds.push(selectedElements[i].id())
    }

    console.log("selected elements:", selectedElements[0].json());
    if (selectedElements.length === 1) {
        let selElem = selectedElements[0].json();
        let vals = selElem.data.id.split("_");
        sendMessage(FROM_MODELER_ACTION_SELECTED_TO_DASHBOARD, {
            id: vals[0],
            gId: vals[1],
            name: selElem.data.name
        })
    }
}

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

Reader ρ (Stream (Of CmdSpec) η ω)

使用 ρ -> Stream (Of CmdSpec) η ω (也由ReaderT ρ (Stream (Of CmdSpec) η) ω 导出),这是定义的monad转换器

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

或者,如果愿意,可以通过包装和展开{-# language GeneralizedNewtypeDeriving #-} 来手动定义实例:

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

CmdY本身就是monad转换器:

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

答案 1 :(得分:0)

Data.Functor.Compose实现您的FunctorApplicative实例。

ReaderT为您实现了一个Monad实例。