F#中的Clojure样式代理

时间:2011-01-28 00:14:47

标签: clojure f#

我正在尝试使用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#中应该有这样的课程吗?我重新发明轮子了吗?

2 个答案:

答案 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)?