开发者

Clojure Style Agents in F#

开发者 https://www.devze.com 2023-02-07 08:04 出处:网络
I\'m trying to code some Clojure style Agents in F# using MailboxProcessors. Here\'s what I have so far:

I'm trying to code some Clojure style Agents in F# using MailboxProcessors. Here's what I have so far:

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)
    mem开发者_如何学Gober self.Deref() =
        state

So the basic idea is that we have a mutable state that can be updated by calling .Send(). My question is, will my messages ever be out of order? If msg A is sent before B will the async function above always process A before B?

Seems like there should be a class like this already in F#? Am I reinventing the wheel?


If msg A is sent before B will the async function above always process A before B?

Yes. (You can see the code for Mailbox

http://fsharppowerpack.codeplex.com/SourceControl/changeset/view/54799#970072

browse to compiler\2.0\Nov2010\src\fsharp\FSharp.Core\control.fs, and eventually see e.g.

   member x.Post(msg) =
       lock syncRoot (fun () ->
           arrivals.Enqueue(msg);
           ...

which shows it's just a queue under a lock.)

Seems like there should be a class like this already in F#? Am I reinventing the wheel?

Well, it's not immediately clear to me how this is different from just updating a mutable global variable willy-nilly (modulo atomicity of simultaneous updates; you said "before" in the question, so I am unclear if that aspect matters to you). What's the context for wanting this?


There is no built-in implementation of the Clojure-style Agent.

I also at one point worked up a quick and dirty F# implementation similar to yours, but did not take the time to consider all the correctness issues involved; in particular, is it not true that 'T may be a value type (a struct) larger than 64 bits (or 32 bits as the case may be) which could cause a tear (I presume that Clojure like Java doesn't have structs to worry about here). Perhaps an F# generic type constraint ('T when 'T : not struct) would be needed?

0

精彩评论

暂无评论...
验证码 换一张
取 消