Applicative
变压器的较弱变体
虽然不可能为 定义一个适用的转换器StateT
,但可以定义一个更弱的变体。我们可以使用, 或等效地使用 ,而不是s -> m (a, s)
状态决定下一个效果的地方(因此m
必须是单子)。m (s -> (a, s))
m (State s a)
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
定义Functor
andApplicative
只是将操作提升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
更新:实际上以上不是必需的,因为两个应用函子的组合始终是一个应用函子(与单子不同)。我们StateTA
与 同构Compose 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)