Alan Mulligan
Alan Mulligan

Reputation: 1198

F# set value of function

I have three functions in a module, SetBehaviour that calls GetBehviour which reads a text file and deserialize it back to my types and return it back to useCases. I then gain acess to the object I want by 'let behavior = useCases.Item(useCaseIdentifier)'

My question is there a way to set 'GlobalBehavior' to the return value of 'SetBehaviour' so i can call 'GlobalBehaviour' directly without going through the reading of the text file and deserialization every time?

let GlobalBehaviour = //The return value of SetBehaviour here


let GetBehaviour =
    let useCases = Data.ReadUseCases
    let deserializedUseCases = JsonConvert.DeserializeObject<Map<string,Types.UseCase>>(useCases)
    deserializedUseCases


let SetBehaviour useCaseIdentifier =
    let useCases = GetBehaviour
    let behavior = useCases.Item(useCaseIdentifier)
    behavior

Upvotes: 1

Views: 139

Answers (2)

Christian
Christian

Reputation: 7852

You could cache the use cases read from file at module initialization like so:

module UseCaseModule
let GlobalBehaviour = //Retreive use case from cachedUseCases and useCaseId
let private cachedUseCases = JsonConvert.DeserializeObject<Map<string,Types.UseCase>>(Data.ReadUseCases)
let mutable private useCaseId = None
let private SetBehaviour useCaseIdentifier =
   useCaseId <- useCaseIdentifier

Upvotes: 2

Tomas Petricek
Tomas Petricek

Reputation: 243096

The answer depends a lot on the context. For example is this some initialization that happens only once, or is it something that changes frequently?

In general, it is better to avoid global mutable state in F# and instead remember the last behaviour somewhere in the module that accesses the module you are showing in your question. That way, the client is in control of the state (and there are various ways to make that nicer). Also, if you were writing a concurrent system, it might make sense to use an agent instead.

However, the basic solution using mutation would look something like this:

let mutable GlobalBehaviour = None // Initially the global behaviour is not set

let SetBehaviour useCaseIdentifier =
    let useCases = GetBehaviour
    let behavior = useCases.Item(useCaseIdentifier)
    GlobalBehaviour <- Some behaviour // Now we set it to the last one
    behaviour

In practice, it might make more sense to use some other approach. For example, if you want to run this just once, you could use a lazy value (which evaluates a function once and caches the result, so that your configuration is not read repeatedly). But it's hard to give a better answer without more details.

Upvotes: 4

Related Questions