为嵌套的 monadic 类型实现 Monad 实例

Implementing Monad instance for a nested monadic type

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

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

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

到目前为止,我已经成功地通过提升实现了这个 3 级深度类型的 FunctorApplicative 实例:

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 变形金刚是可行的方法,您能否也解释一下为什么会这样?

Monad 的组合不如应用程序好。虽然 f (g a) 是应用程序,只要 fg 是(因此您可以编写应用程序实例),但当 f 和 [=14 时,它通常不是 monad =] 是单子。这就是为什么我们需要 monad 转换器而不是应用转换器。

这是一个相关的练习。忘记使用库中的 State,让我们手动处理它的表示。 State s (IO a) 展开为 s -> (IO a, s)。要实现绑定,您将获得

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

你能想出如何将第一个喂给第二个,通过 "statefully" 传递 s 吗?

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

试一试。 (剧透) 在你确信这是不可能的之后,想想是什么让它不可能,以及你需要如何修改类型才能让它成为可能。然后使用该模式定义一个“StateIO s”monad。