写作的常用方法是创建一个封闭捕获局部状态的函数的例子:
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