*
Thursday, 25 February 2016
*

This post is part of a series of posts on implementing a minimal version of QuickCheck from scratch. The source code is available on GitHub.

In this post I’ll be generating random 32-bit floating-point numbers.

In Haskell’s QuickCheck 1.2.0.1 (but also in version 2.8), random 32-bit floating-point numbers are generated as shown below:

```
instance Arbitrary Float where
arbitrary = liftM3 fraction arbitrary arbitrary arbitrary
coarbitrary x = ...
```

Two things are important in the above code:

Here’s the original `fraction`

function in Haskell:

```
fraction :: Fractional a => Integer -> Integer -> Integer -> a
fraction a b c = fromInteger a + (fromInteger b / (abs (fromInteger c) + 1))
```

It takes 3 integers and returns an `a`

which is a fractional (a numeric type that supports the ordinary division operator `/`

).

Here are some sample values generated by fraction:

```
λ> fraction 1 2 3
1.5
λ> fraction 2 2 2
2.6666666666666665
λ> fraction 7 8 9
7.8
```

Now, what I want to do is to call the `fraction`

function passing *random* integers, something like this (pseudo-code):

```
-- Pseudo-code
fraction Gen<int> Gen<int> Gen<int>
```

Here’s where `liftM3`

comes into play:

```
liftM3 :: Monad m => (a1 -> a2 -> a3 -> r) -> m a1 -> m a2 -> m a3 -> m r
```

`a1`

,`a2`

, and`a3`

, correspond to the arguments of`fraction`

`r`

corresponds to the return value of`fraction`

`m a1`

,`m a2`

,`m a3`

will be 3 generators for integers`m r`

the return value (the random float).

So, in F#, a generator for floats can be written as:

```
(* Generates a random real number. *)
let float =
let fraction a b c = float a + float b / (abs (float c) + 1.0)
Gen.lift3 fraction Gen.int Gen.int Gen.int
```

And the `lift3`

function in F# can be written in terms of `apply`

and `return`

:

```
(* Unpacks a function wrapped inside a generator, applying it into a new
generator. *)
let apply f m =
Gen.bind f (fun f' ->
Gen.bind m (fun m' ->
Gen.init (f' m')))
(* Returns a new generator obtained by applying a function to three existing
generators. *)
let lift3 f m1 m2 m3 = Gen.apply (Gen.apply (Gen.apply (Gen.init f) m1) m2) m3
```

Finally, here are some sample floats:

```
> Gen.float |> Gen.generate;;
val it : float = 3.466666667
> Gen.float |> Gen.generate;;
val it : float = 9.352941176
> Gen.float |> Gen.generate;;
val it : float = 18.14285714
> Gen.float |> Gen.generate;;
val it : float = 9.4
> Gen.float |> Gen.generate;;
val it : float = -16.8
> Gen.float |> Gen.generate;;
val it : float = -1.5
> Gen.float |> Gen.generate;;
val it : float = -1.25
> Gen.float |> Gen.generate;;
val it : float = -16.94117647
```

*
This post has been filed under
#fsharp
#quickcheck
*

Have feedback on this page? Let @nikosbaxevanis know on twitter. Need help or found a bug? Contact me.

© 2011-2018 Nikos Baxevanis. All written content on this site is provided under a Creative Commons ShareAlike license. All code is provided under a MIT license unless otherwise stated.