为StateT实现Applicative(< *>)

时间:2015-01-12 13:57:48

标签: haskell monad-transformers applicative

这个问题已被问到before,但没有真正的答案。事实上,接受的答案表明,尽管事实是

,但这是不可能的
  • StateT是Monad,因此是Applicative的超集。因此,标准库只使用(<*>) = ap
  • (正如彼得指出的那样)撰写应用程序总会产生一个应用程序。

MaybeT的其中一个实现我已经阅读过使用过的

liftA2 (<*>) :: (Applicative f, Applicative f1) => f (f1 (a -> b)) -> f (f1 a) -> f (f1 b)

实施Applicative,但我不能在这里工作。我正在进行的工作尝试了以下几个选项:

-- (<*>) :: StateT s f (a -> b) -> State s f a -> State s f b
instance (Applicative f) => Applicative (StateT s f) where
    pure a =  StateT $ \s -> pure (a, s)
    (StateT f) <*> (StateT g) = StateT $ \s ->          -- f :: s -> m (a -> b, s),  g :: s -> m (a, s)
                                    let
                                        mabs = f s          -- mabs :: m (a -> b, s)
                                        mab = fmap fst mabs
                                        ms' = fmap snd mabs

                                    in undefined

我想知道自己错过了什么,希望我能在这个过程中学到一些关于Applicative的知识。

2 个答案:

答案 0 :(得分:4)

Tony使用了一些替代符号,而Simon的答案非常简洁,所以这就是我最终的结果:

-- (<*>) :: StateT s f (a -> b) -> State s f a -> State s f b
instance (Monad f, Applicative f) => Applicative (StateT s f) where
    pure a =  StateT $ \s -> pure (a, s)
    StateT f <*> StateT a =
        StateT $ \s -> 
                f s >>= \(g, t) ->                   -- (f s) :: m (a->b, s)
                    let mapper = \(z, u) -> (g z, u) -- :: (a, s) -> (b, s)
                    in fmap mapper (a t)             -- (a t) :: m (a, s)

我必须声明f也是Monad,但这是可以的,因为它是Monad变换器定义的一部分,正如我所理解的那样。

答案 1 :(得分:2)

实施(取自Tony Morris' functional programming course)可能是

(<*>) :: (Functor f, Monad f) =>
  StateT s f (a -> b)
  -> StateT s f a
  -> StateT s f b
StateT f <*> StateT a =
  StateT (\s -> (\(g, t) -> (\(z, u) -> (g z, u)) <$> a t) =<< f s)