2017-04-16 74 views
1

我心亂如麻混淆StateT,國家和MonadState

之間
newtype StateT s m a = StateT {runStateT :: s -> m (a, s)} 

type State s = StateT s Identity 

class Monad m => MonadState s m | m -> s 
+4

你確切的問題是什麼?你想要完成什麼類型​​的目標?你的困惑來自哪裏?你不知道'newtype','type'和'class'是什麼?如果你只是不理解這些結構,那麼只需閱讀一些Haskell教程。 StackOverflow是針對特定問題的。 – Shersh

+1

問題是...? :) – Alec

回答

4

從前,有一個State類型:

-- Not the current definition. 
newtype State s a = State {runState :: s -> (a, s)} 

State s a值是,在本質上,採取的狀態,併產生一個結果,並更新狀態的功能。合適的Functor,ApplicativeMonad實例使得有可能通過使得元組混排需要處理輸出隱式來更方便地組合這些函數。與操作狀態操作的幾個基本的幫助...

get = State $ \s -> (s, s) 
put s = State $ \_ -> ((), s) 

...它是可能避免的潛在s -> (a, s)類型的任何提及,並編寫代碼感覺狀態。

StateT s是單子變壓器State s之後圖案化:

newtype StateT s m a = StateT {runStateT :: s -> m (a, s)} 

這種變壓器的頂上添加鹼單子,m上述狀態的處理能力。它附帶Functor,ApplicativeMonad實例,以及getput的版本。

如果m,基地單子,在StateT s mIdentity,僞仿...

newtype Identity a = Identity {runIdentity :: a} 

...我們得到的東西等同於普通的舊State s。如此,變壓器State定義爲同義詞...

type State s = StateT s Identity 

...而不是作爲一個單獨的類型。

至於MonadState,它迎合了兩種不同的需求。首先,我們可以使用monad變壓器機器將StateT s m作爲變壓器堆棧中某個其他變壓器的基本monad(任意示例:MaybeT (StateT Int IO))。在這種情況下,使用getput時,需要liftMonadTrans。直接在這樣的情況下使用該業務的一種方式是通過MonadState:它提供了他們作爲方法...

-- Abridged class definition. 
class Monad m => MonadState s m | m -> s where 
    get :: m s 
    put :: s -> m() 
    state :: (s -> (a, s)) -> m a 

...這樣我們就可以對涉及StateT變壓器的任意組合,我們有興趣的情況下, 。

instance Monad m => MonadState s (StateT s m) where -- etc. 
instance MonadState s m => MonadState s (MaybeT m) where -- etc. 
-- And so forth 

其次,如果我們希望有一個比變壓器不同的實現的狀態單子,我們可以把它的MonadState一個實例,讓我們保持相同的基本操作,併爲只要我們寫類型簽名根據MonadState計算,如果需要,可以更容易地更改實現。

2

State是你的正常狀態單子。這是三者中最簡單的。 (在一些老的教程,你可以看到使用State構造,但這已經被替換爲state功能,因爲State s現在是StateT s Identity一個類型別名。)

StateT是爲State單子的單子轉換。它增加了一層通用性,允許你在狀態中放置一個任意monad。這對簡單的解析器很有用,它可以使用例如StateT [Token] Maybe Result將解析表示爲可能失敗的有狀態操作。

MonadState將情況概括得更遠。有一個實例Monad m => MonadState s (StateT s m),但也有一些實例,如允許您在單粒變換器StateT上執行有狀態操作的實例。所有基本狀態功能(getset,modify等)可與MonadState的實例一起使用。