Camilo Telles
Camilo Telles

Reputation: 83

Why this F# function runs only once? I call twice and it runs only once

I wrote the following code to test some MonteCarlo code in F#.

My problem is I only see the random numbers and the "oi" once in my console. I call two times the oneRun function, but it looks that it only runs once.

Here is the code:

let genRandomNumbers count =
    let rnd = System.Random()
    printf "oi "
    List.init count (fun _ -> rnd.NextDouble ())

let oneRun = 
   let numberofClicks = 0
   let randomNumber = genRandomNumbers 50
   let action numberofClicks random = if random <= 0.10 
                                          then numberofClicks+1
                                          else numberofClicks
   randomNumber |> Seq.iter (printf "%f ")
   randomNumber |> List.fold action numberofClicks

[<EntryPoint>]
let main argv = 
    let a = oneRun
    printf "%d " a
    let b = oneRun
    printf "%d " b
    let key_info = Console.ReadKey()
    0 // 

Any hints? Ideas?

Upvotes: 4

Views: 417

Answers (1)

rmunn
rmunn

Reputation: 36688

To expand a little on Mankarse's correct comment, the F# syntax for defining values and functions looks very similar, so it's easy to get confused between them.

This is a value:

let sum = 42

This is a function:

let addThree x = x + 3

Both values and functions can have blocks following them, not just single lines:

let sumWithSideEffects =
    // This will only be evaluated once
    printfn "Side effect happens here"
    42

let addThree x =
    // This will run every time you call the function
    let result = x + 3
    printfn "Added three to %d and got %d" x result
    result

A let declaration that just declares a name is a value. Values are only evaluated once, so any side effects in the value will happen just once. Exactly when they happen is not defined precisely by the language spec, so you can't count on when the side effects will happen. Functions, on the other hand, are evaluated every time the function is called.

Now, when you have a function that takes no parameters, how do you declare it? Well, you declare it by giving it a parameter, but a parameter that doesn't matter. Specifically, you declare that it takes a parameter of type unit. The unit type is a special type in F#. It basically corresponds to an empty tuple, and is written as ().

Think about the empty-tuple type for a minute. If you have a tuple of two bool values, how many possible values can this tuple have? Four: it could be (false, false), or (false, true), or (true, false), or (true, true). If you have a tuple of just one bool, it could have two values: (true) or (false). If you have a tuple of zero values (of whatever type: bool, int, string, doesn't matter), then there's only one possible value it could have: (), the empty tuple. And since that's a type with only one possible value, that's why it's called the unit type.

So if you want a function rather than a value, but that function doesn't need to take any meaningful parameters, you define it like this:

let myFunction () =
    printfn "I'm being called purely for the side effects"

Note how I put a space between the function name and the unit parameter. You don't actually have to have that space there — it's perfectly legal to write let myFunction() = ... — but I want you to see that the () is not just function-declaration syntax, it's an actual value of an actual type. This distinction becomes important when you start doing advanced things with functions, so I want you to be clear about it now.

BTW, normally you'd have a parameter name in your function declaration rather than a value, but the unit type is treated specially: since there's only one possible value of unit, you already know what value your function will be called with, so you don't really need to assign that to a name anyway. So F# lets you declare a function whose input type is unit by just having a () in the parameter list, instead of making you choose a name that you'd never actually use in the function body.

I hope this clears things up for you.

Upvotes: 10

Related Questions