开发者

Style guidelines for global variables in F#

开发者 https://www.devze.com 2023-03-06 21:23 出处:网络
For a project I am working on I need a global variable(technically I don\'t, I could build it and then pass it to every single function call, and let every single function call know about it, but that

For a project I am working on I need a global variable(technically I don't, I could build it and then pass it to every single function call, and let every single function call know about it, but that seems just as hacky, less readable and more work.)

The global variables are look up tables(endgame, opening book and transpositions/cache) for a game.

开发者_如何学JAVA

The fact that some of the code may lose some of it's indempotent behavior is actually the point(speedups) in short, yes I know global mutable state is bad, it's really worth it in this case(10x+ performance improvement)

So here's the question, "build a singleton or use a static value in a static class with combinators"

They are effectively identical but I am curious what people have done before on this sort of problem

Or alternatively, should I be passing the thing around to everyone(or at least a reference to it anyways),is that really the best answer?


Here is a solution similar to the one posted by @Yin Zhu's, but using abstract types to specify a usage interface for the mutable value, a local definition to encapsulate it and object literals to provide an implementation (this is taken from Expert F#--which is co-authored by Don Syme):

type IPeekPoke =
    abstract member Peek: unit -> int
    abstract member Poke: int -> unit

let makeCounter initialState =
    let state = ref initialState
    { new IPeekPoke with
        member x.Poke(n) = state := !state + n
        member x.Peek() = !state }


You can also do it with static fields, like this:

type Common() = 

    static let mutable queue : CloudQueue = null
    static let mutable storageAccount : CloudStorageAccount = null

    static member Queue 
        with get() = queue
        and set v = queue <- v
    static member StorageAccount 
        with get() = storageAccount
        and set v = storageAccount <- v

In another module, just:

open Common
Common.Queue <- xxxx


here is the convention used in F# PowerPack Matrix library (\src\FSharp.PowerPackmath\associations.fs):

// put global variable in a special module
module GlobalAssociations =
    // global variable ht
    let ht = 
        let ht = new System.Collections.Generic.Dictionary<Type,obj>() 
        let optab =
            [ typeof<float>,   (Some(FloatNumerics    :> INumeric<float>) :> obj);
              typeof<int32>,   (Some(Int32Numerics    :> INumeric<int32>) :> obj);
                  ...
              typeof<bignum>,  (Some(BigRationalNumerics   :> INumeric<bignum>) :> obj); ]

        List.iter (fun (ty,ops) -> ht.Add(ty,ops)) optab;
        ht

    // method to update ht
    let Put (ty: System.Type, d : obj)  =
        // lock it before changing
        lock ht (fun () -> 
            if ht.ContainsKey(ty) then invalidArg "ty" ("the type "+ty.Name+" already has a registered numeric association");
            ht.Add(ty, d))
0

精彩评论

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