United Kingdom: +44 (0)208 088 8978

F# 9: That’s so random!

In this blog post, we have a look at a whole range of random functions that were added to the F# collection type modules in F# 9

We're hiring Software Developers

Click here to find out more

This is the first post in our series about F# 9! Keep your eyes out for more posts highlighting shiny new F# features!

A while ago, I wrote this blog post, about taking a random sample out of a list in F#. What I did not know at that time, was that a more permanent solution to that problem had already been introduced in the F# Core library. Now, with the release of F# 9, we have a whole new array of functions to get random items from a collection!

Array.randomSample

Let's start with the issue we encountered in my previous blog post. We wanted to get a random, non-repeating sample from a list. We drew the conclusion that System.Random.GetItems, was not very useful for that, as it allows for repetition. We came up with the following code to solve the issue:

let shuffled array =
    let copy =  Array.copy array
    Random.Shared.Shuffle copy
    copy

let takeRandom array n =
    array
    |> shuffled
    |> Array.take n

With F# 9, we now have the Array.randomSample function (there is also a List and Seq equivalent), that returns N non-repeating samples:

let sample =
    [|"Apple"; "Pear"; "Orange"; "Melon"|]
    |> Array.randomSample 3
// [|"orange"; "Melon"; "Apple"|]

Simple as that! Do note that there are a few failure modes here; the function throws if:

  • The input list is empty (even if you take 0 samples!)
  • The input list contains fewer items than items requested
  • Less than 0 items are requested

Other random operations

Apart from randomSample, there is also:

  • randomChoice source, for getting a single random value:
    let sample =
    [|"Apple"; "Pear"; "Orange"; "Melon"|]
    |> Array.randomChoice
    // "Apple"
  • randomChoices count source, for getting multiple values, allowing repetition:
    let sample =
    [|"Apple"; "Pear"; "Orange"; "Melon"|]
    |> Array.randomChoices 7
    // [|"Melon"; "Pear"; "Orange"; "Pear"; "Orange"; "Apple"; "Apple"|]
  • randomShuffle source, to re-order the values:
    let sample =
    [|"Apple"; "Pear"; "Orange"; "Melon"|]
    |> Array.randomShuffle
    // [|"Melon"; "Orange"; "Pear"; "Apple"|]

    Random sources

You are also very flexible with the source of random you use! All these functions have 3 permutations, each allowing for another source of randomness. The following suffixes are available:

  • no suffix: uses a thread safe random number generator under the hood
  • ...By: takes a function of unit that returns a float between 0.0 and 1.0 as a source of randomness. You could for example use this to create predictable test results
    let sample =
    [|"Apple"; "Pear"; "Orange"; "Melon"|]
    |> Array.randomSampleBy (fun () -> 0.5) 3
    // [|"Orange"; "Pear"; "Melon"|]
  • ...With: Takes an instance of System.Random as a source of randomness:
    let random = System.Random()
    let sample =
    [|"Apple"; "Pear"; "Orange"; "Melon"|]
    |> Array.randomSampleWith random 3
    // [|"Orange"; "Apple"; "Pear"|]

These new functions make working with random values in F# a breeze! Keep an eye out on the blog for more highlights of new F# features, such as nullable reference types, and auto-generated properties on DU cases.