我正在尝试使用MailboxProcessors在F#中编写一些Clojure样式代理。这是我到目前为止所做的:
namespace GameEngine
type Agent<'T>(inital:'T) =
let mutable state:'T = inital
let queue = new MailboxProcessor<'T -> 'T>( fun inbox ->
let rec loop count =
async {
let! msg = inbox.Receive()
state <- msg(state)
return! loop(count + 1)
}
loop 0)
do
queue.Start()
member self.Send(action:'T -> 'T) =
queue.Post(action)
member self.Deref() =
state
所以基本的想法是我们有一个可变状态,可以通过调用.Send()来更新。我的问题是,我的消息是否会出现故障?如果在B之前发送消息,则上面的异步函数总是在B之前处理A?
好像在F#中应该有这样的课程吗?我重新发明轮子了吗?
答案 0 :(得分:2)
如果在B之前发送msg A,上面的异步功能总是在B之前处理A?
是。 (您可以看到邮箱的代码
http://fsharppowerpack.codeplex.com/SourceControl/changeset/view/54799#970072
浏览编译器\ 2.0 \ Nov2010 \ src \ fsharp \ FSharp.Core \ control.fs,最终看到例如。
member x.Post(msg) =
lock syncRoot (fun () ->
arrivals.Enqueue(msg);
...
表明它只是一个锁定下的队列。)
好像在F#中应该有这样的课程吗?我重新发明轮子了吗?
嗯,我不能立即明白这与仅仅更新一个可变的全局变量(同时更新的模数原子性;你在问题中说“之前”)有什么不同,所以我不清楚这个方面是否重要您)。想要这个的背景是什么?
答案 1 :(得分:1)
没有Clojure风格代理的内置实现。
我还在某一点上编写了一个类似于你的快速而肮脏的F#实现,但没有花时间考虑所涉及的所有正确性问题;特别是,'T可能是值类型(一个struct
)大于64位(或32位,视情况而定)并不是真的可能导致撕裂(我认为像Java这样的Clojure没有结构担心这里。也许需要F#泛型类型约束('T when 'T : not struct
)?