是否可以实现`(Applicative m)=>适用(StateT s m)`?

时间:2013-09-07 12:56:10

标签: haskell monad-transformers state-monad

我目前正在处理Data.FreshControl.Monad.Trans.Fresh。定义用于生成新变量的接口,以及实现此接口的monad转换器。

我最初认为可以为Applicative实施FreshT v m个实例,只要求Applicative m存在。但是,我卡住了,似乎我需要Monad m。不相信我的Haskell-fu,然后我转向变形金刚包,并对我在Control.Monad.Trans.State.Lazy.Strict中发现的内容感到惊讶:

instance (Functor m, Monad m) => Applicative (StateT s m) where
    pure = return
    (<*>) = ap

所以这是我的问题:是否可以使用以下实例头创建具有等效语义的实例?

instance (Applicative m) => Applicative (StateT s m) where

3 个答案:

答案 0 :(得分:13)

考虑您有两个功能:

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

您想要创建一个函数h = StateT f <*> StateF g

 h :: s -> m (s, b)

从上面你有s你可以传递给f所以你有:

 f' :: m (s, a -> b)
 g :: s -> m (s, a)

但要从s中获取f',你需要Monad(无论你使用的是什么,它都会以m s的形式存在,所以你将无法申请值为g)。

您可以使用定义并使用free monad但是对于状态崩溃,您需要join

答案 1 :(得分:6)

Applicative转换器

的较弱变体

虽然无法为StateT定义应用变换器,但可以定义一个有效的较弱变量。我们可以使用s -> m (a, s)或等效m,而不是m (s -> (a, s)),状态决定下一个效果(因此m (State s a)必须是monad)。

import Control.Applicative
import Control.Monad
import Control.Monad.State
import Control.Monad.Trans

newtype StateTA s m a = StateTA (m (State s a))

这严重弱于StateT。每个StateTA都可以设为StateT(但反之亦然):

toStateTA :: Applicative m => StateTA s m a -> StateT s m a
toStateTA (StateTA k) = StateT $ \s -> flip runState s <$> k

定义FunctorApplicative只是将State的操作解除为基础m

instance (Functor m) => Functor (StateTA s m) where
    fmap f (StateTA k) = StateTA $ liftM f <$> k
instance (Applicative m) => Applicative (StateTA s m) where
    pure = StateTA . pure . return
    (StateTA f) <*> (StateTA k) = StateTA $ ap <$> f <*> k    

我们可以定义lift的适用变体:

lift :: (Applicative m) => m a -> StateTA s m a
lift = StateTA . fmap return

更新:实际上上面没有必要,因为两个应用函子的组合总是一个应用函子(不像monads)。我们的StateTACompose m (State s)同构,自动为Applicative

instance (Applicative f, Applicative g) => Applicative (Compose f g) where
    pure x = Compose (pure (pure x))
    Compose f <*> Compose x = Compose ((<*>) <$> f <*> x)

因此我们可以写

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Control.Applicative
import Control.Monad.State
import Data.Functor.Compose

newtype StateTA s m a = StateTA (Compose m (State s) a)
    deriving (Functor, Applicative)

答案 2 :(得分:5)

虽然如前面的答案所述,这个实例一般无法定义,但值得注意的是,当fApplicatives为{{1}时},Monoid也是StateT s f,因为它可以被视为应用函子的组合:

Applicative