Рекомендации для глобальных переменных в F#
для проекта, над которым я работаю, мне нужна глобальная переменная(технически я этого не делаю, я мог бы построить ее, а затем передать ее каждому вызову функции, и пусть каждый вызов функции знает об этом, но это кажется таким же хакерским, менее читаемым и больше работы.)
глобальные переменные-это поиск таблиц (Эндшпиль, открытие книги и транспозиции/кэш) для игры.
тот факт, что некоторые из кода могут потерять некоторые из его беспомощного поведения на самом деле короче говоря, да, я знаю, что глобальное изменчивое состояние плохо, это действительно стоит в этом случае (10x + улучшение производительности)
Итак, вот вопрос: "создайте синглтон или используйте статическое значение в статическом классе с комбинаторами"
Они фактически идентичны, но мне любопытно, что люди делали раньше по этой проблеме
или, альтернативно, должен ли я передавать вещь всем (или, по крайней мере, ссылку на нее в любом случае), это действительно лучший ответ?
3 ответов
вот соглашение, используемое в Матричной библиотеке F# PowerPack (\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))
вот решение, подобное тому, которое опубликовано @Yin Zhu, но с использованием абстрактных типов для указания интерфейса использования для изменяемого значения, локального определения для его инкапсуляции и объектных литералов для обеспечения реализации (это взято из Expert F#-который является соавтором 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 }
вы также можете сделать это со статическими полями, например:
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
в другом модуле, просто:
open Common
Common.Queue <- xxxx