寫作的常用方法是創建一個封閉捕獲局部狀態的函數的例子:
let getNextAlias =
let count = ref 0
(fun() ->
count := !count + 1;
sprintf "t%d" (!count))
類型的getNextAlias
簡直是unit -> string
和當你重複地調用它時,它會返回字符串「t1」,「t2」,...這依賴於可變狀態,但是可變狀態對用戶是隱藏的。
至於是否可以做到這一點沒有可變狀態 - 簡單的答案是否定的,因爲當你調用具有相同參數的純功能性功能的兩倍,它必須返回相同的結果。因此,你必須寫東西用以下結構:
let alias, state1 = getNextAlias state0
printf "first alias %s" alias
let alias, state2 = getNextAlias state1
printf "second alias %s" alias
// ...
正如你所看到的,你需要保留一些狀態,並在整個代碼維護。在F#中,處理這個問題的標準方法是使用可變狀態。在Haskell中,你可以使用國家單子,它允許您隱藏狀態的傳遞。使用實施from this question,你可以寫這樣的:
let getNextAlias = state {
let! n = getState
do! setState (n + 1)
return sprintf "t%d" n }
let program =
state {
let! alias1 = getNextAlias()
let! alias2 = getNextAlias()
// ...
}
execute progam 0 // execute with initial state
這是很相似的其他計算如lazy
或seq
,實際上 - 在state { .. }
塊計算有一定的狀態,你可以通過提供初始值執行它們的狀態。然而,除非你有充分的理由要求純粹的功能解決方案,否則我更喜歡實際的F#編程的第一個版本。
這很有幫助。你看到沒有聲明可變狀態的任何方式嗎? – Daniel 2010-05-19 21:03:46
我可能會補充一件事:你可以使用'incr count'而不是'count:=!count + 1' – Daniel 2010-05-19 21:07:25
我意識到必須有可變狀態_somewhere_,但我喜歡它以隱藏在預定義的模式(例如,懶惰,seq)。 – Daniel 2010-05-19 21:15:57