WereGoingOcean
WereGoingOcean

Reputation: 108

F# calling function that returns record in for loop only executes once

I mainly work in C# and am new to F#/function languages and I'm having a problem with a pretty simple program. I have a function that creates a record with two integer fields. The fields are chosen System.Random.NextDouble inside a match to align with certain probabilities. I then have a for loop that should run the createCustomer function four times.

The problem I'm having is that the Customer is the same for all 10 iterations of the for loop and the printfn inside of getIATime only seems to execute once.

Program.fs

open Simulation

[<EntryPoint>]
let main argv = 
    printfn "%A" argv
    printfn "Test"

    for i in 1 .. 10 do
        let mutable customer = createCustomer
        printfn "i: %d\tIA: %d\tService: %d" i customer.interArrivalTime customer.serviceTime


    ignore (System.Console.ReadLine()) //Wait for keypress @ the end
    0 // return an integer exit code

Simulation.fs

module Simulation

type Customer = {
    interArrivalTime: int
    serviceTime: int
}

let createCustomer =
    let getRand =
        let random = new System.Random()
        fun () -> random.NextDouble()

    let getIATime rand =
        printf "Random was: %f\n" rand 
        match rand with
        | rand when rand <= 0.09 -> 0
        | rand when rand <= 0.26 -> 1
        | rand when rand <= 0.53 -> 2
        | rand when rand <= 0.73 -> 3
        | rand when rand <= 0.88 -> 4
        | rand when rand <= 1.0 -> 5

    let getServiceTime rand =
        match rand with
        | rand when rand <= 0.2 -> 1
        | rand when rand <= 0.6 -> 2
        | rand when rand <= 0.88 -> 3
        | rand when rand <= 1.0 -> 4

    {interArrivalTime = getIATime (getRand()); serviceTime = getServiceTime (getRand())}

Upvotes: 1

Views: 649

Answers (1)

Fyodor Soikin
Fyodor Soikin

Reputation: 80744

Your getCustomer is not a function, but a value. Its body is executed only once during program initialization, and the result is stored in a field, which can then be accessed. When you think that you "call" the function, you actually merely reference the value. No calling is going on, because there is nothing to call.

To make getCustomer a function, give it a parameter. This is how functions differ from values in F#: if you have a parameter, you're a function; if not - you're a value. Since there is no actual data that you'd want to pass to the function, you can give it a "dummy" ("placeholder") parameter of type unit. This type has exactly one value, and that value is written as ():

let createCustomer () =
    let getRand =
        let random = new System.Random()
        fun () -> random.NextDouble()

    ...

Then call it like this:

for i in 1 .. 10 do
    let mutable customer = createCustomer()
    printfn "i: %d\tIA: %d\tService: %d" i customer.interArrivalTime customer.serviceTime

Upvotes: 4

Related Questions