Рекомендации по стилю для глобальных переменных в F#

#f# #coding-style #global-variables

#f# #стиль кодирования #глобальные переменные

Вопрос:

Для проекта, над которым я работаю, мне нужна глобальная переменная (технически у меня ее нет, я мог бы создать ее, а затем передавать в каждый отдельный вызов функции и сообщать об этом каждому отдельному вызову функции, но это кажется таким же халтурным, менее читаемым и более трудоемким.)

Глобальными переменными являются таблицы поиска (эндшпиль, вступительная книга и транспозиции / кэш) для игры.

Тот факт, что часть кода может потерять часть своего независимого поведения, на самом деле является точкой (ускорения) короче говоря, да, я знаю, что глобальное изменяемое состояние плохое, в данном случае это действительно того стоит (повышение производительности в 10 раз )

Итак, вот вопрос: «создайте синглтон или используйте статическое значение в статическом классе с комбинаторами»

Они фактически идентичны, но мне любопытно, что люди делали раньше с такого рода проблемами

Или, в качестве альтернативы, я должен передавать эту вещь всем (или, по крайней мере, ссылку на нее в любом случае), это действительно лучший ответ?

Ответ №1:

Вот решение, аналогичное тому, которое опубликовал @Yin Zhu, но использующее абстрактные типы для указания интерфейса использования для изменяемого значения, локальное определение для его инкапсуляции и объектные литералы для обеспечения реализации (это взято из Expert F #, соавтором которого является Дон Сайм):

 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 }
  

Ответ №2:

Вы также можете сделать это со статическими полями, например, так:

 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
  

Ответ №3:

вот соглашение, используемое в матричной библиотеке F # PowerPack ( srcFSharp.PowerPackmathassociations.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))
  

Комментарии:

1. Я несколько раз видел, как люди создавали модуль с общедоступными ссылочными типами. Я не уверен, какая из них «более рекомендуется», вероятно, это зависит от того, экспортируете ли вы позже в other . Чистый язык или нет.