2013-11-24 24 views
1

這一次可能是一個愚蠢的一個,但在看看(Eliminating my explicit state passing via like, monads and stuff包裝狀態monad有什麼優點?

type State<'s,'a> = State of ('s -> 'a * 's) 

type StateBuilder<'s>() = 
    member x.Return v : State<'s,_> = State(fun s -> v,s) 
    member x.Bind(State v, f) : State<'s,_> = 
    State(fun s -> 
     let (a,s) = v s 
     let (State v') = f a 
     v' s) 

let withState<'s> = StateBuilder<'s>() 

let getState = State(fun s -> s,s) 
let putState v = State(fun _ ->(),v) 

let runState (State f) init = f init 

什麼是State包裝's -> 'a * 's的優勢。這只是一種安全預防措施嗎?

+0

這看起來是http://stackoverflow.com/q/2595673/701062 –

+0

@ Gary.S的副本這個問題是問爲什麼狀態monad實現與函數而不是元組,而不是爲什麼狀態函數有時被另一種類型包裹。 –

回答

3

我認爲這是一個比安全更偏向或方便的問題;有些人喜歡把這個函數包裝在一個單一的區分類型的工會類型中,有些人則不這樣做。

我不喜歡包裝這些函數,因爲它引入了少量額外的開銷,並且可以禁止編譯器進行一些優化。在我ExtCore庫,我已經實現了同樣的事情,使用類型別名,而不是創建一個實際的類型來封裝功能:

type StateFunc<'State, 'T> = 'State -> 'T * 'State 
2

我的猜測是包裝來自哈斯克爾傳統和語言,可以概括超過單子。 在那些laguanges中,你可以有一個通用的>>=函數,但每個類型只能有一個實現,有時候有多個有用的實現。

這是非常通用的類型,如'a * 'b'a->'b的情況。

對於函數'a -> 'b您可以定義一個讀取器,一個狀態或一個語法分析器monad,告訴哪個實現選擇要包裝它們,因此它們具有不同的類型。

在F#中,情況不同,大多數monad庫沒有定義通用的>>=實現,因爲在.NET中沒有乾淨的方式來執行此操作,所以不需要包裝狀態,因爲您將明確地應用具體實現>>=等monad相關函數。

如果沒有泛型函數或重載,如果你願意,你仍然可以包裝你的狀態monad,但是你必須在Haskell中打包和解包代碼,在這種情況下,這個決定取決於你想要的數量定製你的類型,這是一個general question,而不僅僅是monads。