[Haskell] State Monad和狀態(tài)轉(zhuǎn)移過程

初識狀態(tài)

先看一個小游戲项贺,這個小游戲用字符串來控制君躺,最后得到總分峭判。
c用來啟動和停止計分,在啟動計分狀態(tài)下a加一分棕叫,在停止計分狀態(tài)下b減一分林螃。
本例中用abcaaacbbcabbab控制,最終得分為2俺泣。

module Main where
import Control.Monad.State

-- Example use of State monad
-- Passes a string of dictionary {a,b,c}
-- Game is to produce a number from the string.
-- By default the game is off, a C toggles the
-- game on and off. A 'a' gives +1 and a b gives -1.
-- E.g 
-- 'ab'    = 0
-- 'ca'    = 1
-- 'cabca' = 0
-- State = game is on or off & current score
--       = (Bool, Int)

type GameValue = Int
type GameState = (Bool, Int)
 
playGame :: String -> State GameState GameValue
playGame []     = do
    (_, score) <- get
    return score
 
playGame (x:xs) = do
    (on, score) <- get
    case x of
         'a' | on -> put (on, score + 1)
         'b' | on -> put (on, score - 1)
         'c'      -> put (not on, score)
         _        -> put (on, score)
    playGame xs
 
startState = (False, 0)
 
main = print $ evalState (playGame "abcaaacbbcabbab") startState

定義State Monad

-- 's' is the state, 'a' is the value
newtype State s a = State {
    runState :: s -> (a, s)
}

returnState :: a -> State s a
returnState a = State $ \s -> (a, s)

bindState :: State s a -> (a -> State s b) -> State s b
bindState m k = State $ \s -> runState (k a) s'
    where (a, s') = runState m s

instance Monad (State s) where
    m >>= k = bindState m k
    return a = returnState a

注意其中某些值的類型:

runState :: State s a -> s -> (a, s)
m :: State s a
k :: a -> State s b

還需注意治宣,State s a中的s是類型,而\s -> ...中的s是值砌滞。

單步狀態(tài)轉(zhuǎn)移

-- runState (return 'a') 1 = ('a', 1)
return :: a -> State s a
return x = State $ \s -> (x, s)

-- runState get 1 = (1, 1)
get :: State s a
get = State $ \s -> (s, s)

-- runState (put 5) 1 = ((), 5)
put :: a -> State s ()
put x = State $ \s -> ((), x)

-- evalState (return 'a') 1 = 'a'
evalState :: State s a -> s -> a
evalState s = fst . runState s

-- execState (return 'a') 1 = 1
execState :: State s a -> s -> s
execState s = snd . runState s

用do-notation組合多步轉(zhuǎn)移

因為(State s)是Monad的實例,
所以坏怪,類型State s a的值是一個monad value(也稱為action
action中包裝了類型為a的值贝润。

do-notation可以把各個action串聯(lián)起來。
還可以提取各action中包裝的值铝宵,進行傳遞打掘。

-- runState (do {put 5; return 'a'}) 1 = ('a', 5)
-- runState (do {x <- get; put (x+1); return x) 1 = (1, 2)
-- runState (do {x <- get; put (x-1); get) 1 = (0, 0)

這里詳細(xì)解釋一下runState (do {put 5; return 'a'}) 1的執(zhí)行過程,

-- put 5 = State $ \s -> ((), 5)
-- return 'a' = State $ \s -> ('a', s)

-- do {put 5; return 'a'} 
-- = (put 5) >>= (\_ -> (return 'a'))
-- = (State $ \s -> ((), 5)) >>= (\_ -> (State $ \s -> ('a', s)))
-- = bindState (State $ \s -> ((), 5)) (\_ -> (State $ \s -> ('a', s)))
-- = State $ \s -> runState ((\_ -> (State $ \s -> ('a', s))) a) s' where (a, s') = runState (State $ \s -> ((), 5)) s
-- = State $ \s -> ('a', 5)

-- runState (do {put 5; return 'a'}) 1
-- = runState (State $ \s -> ('a', 5)) 1
-- = ('a', 5)

總結(jié)

evalState 狀態(tài)轉(zhuǎn)移過程 初始狀態(tài)鹏秋,從初始狀態(tài)出發(fā)尊蚁,最終得到一個結(jié)果值
execState 狀態(tài)轉(zhuǎn)移過程 初始狀態(tài)侣夷,從初始狀態(tài)出發(fā)横朋,最終得到一個結(jié)果狀態(tài)
runState 狀態(tài)轉(zhuǎn)移過程 初始狀態(tài)百拓,從初始狀態(tài)出發(fā)琴锭,最終得到一個元組(結(jié)果值, 結(jié)果狀態(tài))

狀態(tài)轉(zhuǎn)移過程可以是狀態(tài)的單步轉(zhuǎn)移衙传,也可以是用do-notation串聯(lián)起來的多步轉(zhuǎn)移决帖。
因此,State Monad的做法蓖捶,可以看做將狀態(tài)轉(zhuǎn)移過程固化下來地回,最后再一次性從初始狀態(tài)轉(zhuǎn)移到最終狀態(tài)。

參考:

State Monad - HaskellWiki

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末俊鱼,一起剝皮案震驚了整個濱河市刻像,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌亭引,老刑警劉巖绎速,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異焙蚓,居然都是意外死亡纹冤,警方通過查閱死者的電腦和手機洒宝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萌京,“玉大人雁歌,你說我怎么就攤上這事≈校” “怎么了靠瞎?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長求妹。 經(jīng)常有香客問我乏盐,道長,這世上最難降的妖魔是什么制恍? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任父能,我火速辦了婚禮,結(jié)果婚禮上净神,老公的妹妹穿的比我還像新娘何吝。我一直安慰自己,他們只是感情好鹃唯,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布爱榕。 她就那樣靜靜地躺著,像睡著了一般坡慌。 火紅的嫁衣襯著肌膚如雪黔酥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天八匠,我揣著相機與錄音絮爷,去河邊找鬼。 笑死梨树,一個胖子當(dāng)著我的面吹牛坑夯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抡四,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼柜蜈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了指巡?” 一聲冷哼從身側(cè)響起淑履,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎藻雪,沒想到半個月后秘噪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡勉耀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年指煎,在試婚紗的時候發(fā)現(xiàn)自己被綠了蹋偏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡至壤,死狀恐怖威始,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情像街,我是刑警寧澤黎棠,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站镰绎,受9級特大地震影響脓斩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜畴栖,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一俭厚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧驶臊,春花似錦、人聲如沸叼丑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸠信。三九已至纵寝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間星立,已是汗流浹背爽茴。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绰垂,地道東北人室奏。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像劲装,于是被迫代替她去往敵國和親胧沫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理占业,服務(wù)發(fā)現(xiàn)绒怨,斷路器,智...
    卡卡羅2017閱讀 134,651評論 18 139
  • 本文為翻譯谦疾,個人學(xué)習(xí)之用南蹂,原地址 程序狀態(tài) 如果你以前有其他語言的編程經(jīng)驗,你可能寫過一些函數(shù)或者方法來控制程序的...
    ParkinWu閱讀 3,026評論 0 3
  • 一. 增強學(xué)習(xí)簡介 1.1 什么是增強學(xué)習(xí)念恍? 機器學(xué)習(xí)的算法可以分為三類:監(jiān)督學(xué)習(xí)六剥,非監(jiān)督學(xué)習(xí)和增強學(xué)習(xí)晚顷。 增強學(xué)...
    阿阿阿阿毛閱讀 31,148評論 0 25
  • 今天要扒的還是周冬雨。 希望你們不要審美疲勞仗考。 其實明星的套路還是深情音同,我們并不是那么關(guān)心。 好吧秃嗜,讓我們進入主題...
    堂姐珠寶家閱讀 7,802評論 0 1
  • 對于這種劇情 一直到十多年后的今天 還是有很多人難以忘懷 我從四月四號到今天 四月十六號 刷了一遍 并且還在念念不...
    炫酷杏仙兒閱讀 195評論 0 0