Reputation: 1664
I need a global variable (I could build it, 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 lookup tables (endgame: opening book and transpositions/cache) for a game.
That some of the code may lose its idempotent behavior is actually the point (speedups). I know global mutable state is bad but it's worth it (10x+ performance improvement). So how do I 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 on this sort of problem. Or should I be passing the thing around to everyone (or at least a reference)?
Upvotes: 7
Views: 2998
Reputation: 126
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
Upvotes: 3
Reputation: 2040
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 }
Upvotes: 5
Reputation: 17119
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))
Upvotes: 2