Reputation: 83
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
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