实现嵌套的单体类型的Monad实例。

问题描述 投票:1回答:1

作为Haskell自学练习的一部分,我正在尝试推导出一个叫做 Monad 我的类型的实例。该类型定义为

newtype ParsePackUnpack f a = ParsePackUnpack
  {
    unparse:: State PackUnpackState (Ap f a)
  }

其中 Ap f a 来自 Data.Monoid. 对于我的类型,我想说的是,解析是一个有状态的操作,结果是任何一个 monoid.

到目前为止,我已经成功实施了 FunctorApplicative 实例,但我无法为我的类型正确导出一个Monad实例。

instance Functor f => Functor (ParsePackUnpack f) where
  fmap f ma =
    let f' = fmap f     -- lift (a -> b) to (Ap f a -> Ap f b)
     in ParsePackUnpack $ f' <$> (unparse ma)

instance Applicative f => Applicative (ParsePackUnpack f) where
  pure = ParsePackUnpack . pure . pure

  f <*> ma =
    let f' = liftA2 (<*>) . unparse $ f       -- lift Ap f (a -> b) -> Ap f a -> Ap f b to State s (Ap f a) -> State s (Ap f b)
     in ParsePackUnpack $ f' (unparse ma)     -- Apply to State s (Ap f a)

但是我不能正确地导出一个Monad实例给我的类型。经过一些类型分析,这是我最新的尝试。

instance Monad f => Monad (ParsePackUnpack f) where
  return = ParsePackUnpack . return . return

  ma >>= f = ParsePackUnpack . state $ \st ->
    let (a, s) = runState (unparse ma) st
        res = a >>= fst . flip runState s . unparse . f -- fst ignores state from the result
    in (res, s)

我相信这是不正确的,因为我忽略了状态的存在 res 的操作。

正确的实现方式是什么?>>= 的操作?由于这是一个学习的过程,我试图避免使用Monad变换器。如果 Monad 变换器是最好的方法,您能解释一下为什么会这样吗?

haskell monads state-monad
1个回答
6
投票

Monad不像applicatives那样好编译。而 f (g a) 是适用性的,只要 fg 是(因此你有能力写出应用实例),它一般不是一个单体,当 fg 是单项式。这就是为什么我们需要单项式变换器而不需要应用式变换器的原因。

下面是一个相关的练习。 忘记使用 State 从库中取出,让我们手动处理它的表示。State s (IO a) 展开到 s -> (IO a, s). 要实现bind,你将得到

f :: s -> (IO a, s)
g :: a -> s -> (IO b, s)

你能不能想出如何将第一种喂给第二种,通过。s 通过 "statefully"?

bound :: s -> (IO b, s)
bound s0 = ??

给它一个尝试。还有 (破坏者) 在你说服自己这是不可能的之后,想一想是什么使它不可能,以及你需要如何修改类型来使它成为可能。 然后用这个模式来定义一个"StateIO s"单子。

© www.soinside.com 2019 - 2024. All rights reserved.