Yếu của một biến Applicative
Mặc dù nó không phải là có thể xác định một biến applicative cho StateT
, có thể xác định một biến thể yếu hơn hoạt động. Thay vì có s -> m (a, s)
, trong đó trạng thái quyết định hiệu ứng tiếp theo (do đó m
phải là một đơn nguyên), chúng tôi có thể sử dụng m (s -> (a, s))
hoặc tương đương 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))
Điều này hoàn toàn yếu hơn StateT
.Mỗi StateTA
thể được làm thành StateT
(nhưng không phải ngược lại):
toStateTA :: Applicative m => StateTA s m a -> StateT s m a
toStateTA (StateTA k) = StateT $ \s -> flip runState s <$> k
Xác định Functor
và Applicative
chỉ là vấn đề thời nâng hoạt động của State
vào cơ bản 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
Và chúng ta có thể xác định một biến thể ứng dụng của lift
:
lift :: (Applicative m) => m a -> StateTA s m a
lift = StateTA . fmap return
Cập nhật: Thực tế ở trên không cần thiết vì thành phần của hai ứng viên luôn là một hàm functor (không giống như monads). StateTA
của chúng tôi là đẳng cấu với Compose m (State s)
, tự động là Applicative
:
instance (Applicative f, Applicative g) => Applicative (Compose f g) where
pure x = Compose (pure (pure x))
Compose f <*> Compose x = Compose ((<*>) <$> f <*> x)
Vì vậy chúng tôi có thể viết chỉ
{-# 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)
Nguồn
2013-09-07 17:37:18
Điều thú vị là, có máy biến áp khác (ví dụ, 'WriterT',' ExceptT'), mà ' Ví dụ ứng dụng yêu cầu hàm tạo kiểu cơ bản là 'Monad'. – kirelagin