# Combining Random Values

<div class="callout callout-info"> In addition to the standard imports given at the start of the chapter, in this section we're assuming the following:

``import doodle.random._``

</div>

So far we've seen how to represent functions generating random values using the `Random` type, and how to make deterministic transformations of a random value using `map`. In this section we'll see how we can make a random (or stochastic, if you prefer fancier words) transformation of a random value using `flatMap`.

To motivate the problem lets try writing `randomConcentricCircles`, which will generate concentric circles with randomly chosen hue using the utility methods we developed in the previous section.

We start with the code to create concentric circles with deterministic colors and the utilities we developed previously.

``````def concentricCircles(count: Int, size: Int, color: Color): Image =
count match {
case 0 => Image.empty
case n =>
Image.circle(size).fillColor(color).on(concentricCircles(n-1, size + 5, color.spin(15.degrees)))
}

val randomAngle: Random[Angle] =
Random.double.map(x => x.turns)

def randomColor(s: Double, l: Double): Random[Color] =
randomAngle map (hue => Color.hsl(hue, s, l))

def randomCircle(r: Double, color: Random[Color]): Random[Image] =
color.map(fill => Image.circle(r).fillColor(fill))``````

Let's create a method skeleton for `randomConcentricCircles`.

``````def randomConcentricCircles(count: Int, size: Int): Random[Image] =
???``````

The important change here is we return a `Random[Image]` not an `Image`. We know this is a structural recursion over the natural numbers so we can fill out the body a bit.

``````def randomConcentricCircles(count: Int, size: Int): Random[Image] =
count match {
case 0 => ???
case n => ???
}``````

The base case will be `Random.always(Image.empty)`, the direct of equivalent of `Image.empty` in the deterministic case.

``````def randomConcentricCircles(count: Int, size: Int): Random[Image] =
count match {
case 0 => Random.always(Image.empty)
case n => ???
}``````

What about the recursive case? We could try using

``val randomPastel = randomColor(0.7, 0.7)``
``````def randomConcentricCircles(count: Int, size: Int): Random[Image] =
count match {
case 0 => Image.empty
case n =>
randomCircle(size, randomPastel).on(randomConcentricCircles(n-1, size + 5))
}
// error:
// Found:    (doodle.image.Image.empty : doodle.image.Image)
// Required: doodle.random.Random[doodle.image.Image]
//     case 0 => randomColor.map{ c => coloredRectangle(c) }
//                          ^
// error:
// value on is not a member of doodle.random.Random[doodle.image.Image]
// error:
// Line is indented too far to the left, or a `}` is missing
// error:
// Line is indented too far to the left, or a `}` is missing
// error:
// Line is indented too far to the left, or a `}` is missing
//   randomAngle.map(hue => Color.hsl(hue, s, l))
//                                               ^
// error:
// Line is indented too far to the left, or a `}` is missing
// def randomConcentricCircles(count: Int, size: Int): Random[Image] =
//                                                                    ^
// error:
// Line is indented too far to the left, or a `}` is missing
//         randomConcentricCircles(n-1, size + 5).map{ circles =>
//                                                               ^
// error:
// Line is indented too far to the left, or a `}` is missing
//         }
//          ^``````

but this does not compile. Both `randomConcentricCircles` and `randomCircle` evaluate to `Random[Image]`. There is no method `on` on `Random[Image]` so this code doesn't work.

Since this is a transformation of two `Random[Image]` values, it seems like we need some kind of method that allows us to transform two `Random[Image]`, not just one like we can do with `map`.
We might call this method `map2` and we could imagine writing code like

``````randomCircle(size, randomPastel).map2(randomConcentricCircles(n-1, size + 5)){
(circle, circles) => circle on circles
}``````

Presumably we'd also need `map3`, `map4`, and so on. Instead of these special cases we can use `flatMap` and `map` together.

``````randomCircle(size, randomPastel) flatMap { circle =>
randomConcentricCircles(n-1, size + 5) map { circles =>
circle on circles
}
}``````

The complete code becomes

``````def randomConcentricCircles(count: Int, size: Int): Random[Image] =
count match {
case 0 => Random.always(Image.empty)
case n =>
randomCircle(size, randomPastel).flatMap{ circle =>
randomConcentricCircles(n-1, size + 5).map{ circles =>
circle.on(circles)
}
}
}``````

Example output is shown in Figure generative:random-concentric-circles. Let's now look closer at this use of `flatMap` and `map` to understand how this works.

### Type Algebra

The simplest way, in my opinion, to understand why this code works is to look at the types. The code in question is

``````randomCircle(size, randomPastel) flatMap { circle =>
randomConcentricCircles(n-1, size + 5) map { circles =>
circle on circles
}
}``````

Starting from the inside, we have

``````{ circles =>
circle on circles
}``````

which is a function with type

``Image => Image``

Wrapping this we have

``````randomConcentricCircles(n-1, size + 5) map { circles =>
circle on circles
}``````

We known `randomConcentricCircles(n-1, size + 5)` has type `Random[Image]`. Substituting in the `Image => Image` type we worked out above we get

``Random[Image] map (Image => Image)``

Now we can deal with the entire expression

``````randomCircle(size, randomPastel) flatMap { circle =>
randomConcentricCircles(n-1, size + 5) map { circles =>
circle on circles
}
}``````

`randomCircle(size, randomPastel)` has type `Random[Image]`. Performing substitution again gets us a type equation for the entire expression.

``Random[Inage] flatMap (Random[Image] map (Image => Image))``

Now we can apply the type equations for `map` and `flatMap` that we saw earlier:

``````F[A] map (A => B) = F[B]
F[A] flatMap (A => F[B]) = F[B]``````

Working again from the inside out, we first use the type equation for `map` which simplifies the type expression to

``Random[Inage] flatMap (Random[Image])``

Now we can apply the equation for `flatMap` yielding just

``Random[Image]``

This tells us the result has the type we want. Notice that we've been performing substitution at the type level---the same technique we usually use at the value level.

### Exercises {-}

Don't forget to import `doodle.random._` when you attempt these exercises.

#### Randomness and Randomness {-}

What is the difference between the output of `programOne` and `programTwo` below? Why do they differ?

``````def randomCircle(r: Double, color: Random[Color]): Random[Image] =
color.map(fill => Image.circle(r).fillColor(fill))

def randomConcentricCircles(count: Int, size: Int): Random[Image] =
count match {
case 0 => Random.always(Image.empty)
case n =>
randomCircle(size, randomPastel).flatMap{ circle =>
randomConcentricCircles(n-1, size + 5).map{ circles =>
circle.on(circles)
}
}
}

val circles = randomConcentricCircles(5, 10)
val programOne =
circles.flatMap{ c1 =>
circles.flatMap{ c2 =>
circles.map{ c3 =>
c1.beside(c2).beside(c3)
}
}
}

val programTwo =
circles map { c => c beside c beside c }``````

<div class="solution"> `programOne` displays three different circles in a row, while `programTwo` repeats the same circle three times. The value `circles` represents a program that generates an image of randomly colored concentric circles. Remember `map` represents a deterministic transform, so the output of `programTwo` must be the same same circle repeated thrice as we're not introducing new random choices. In `programOne` we merge `circle` with itself three times. You might think that the output should be only one random image repeated three times, not three, but remember `Random` preserves substitution. We can write `programOne` equivalently as

``````val programOneRewritten =
randomConcentricCircles(5, 10) flatMap { c1 =>
randomConcentricCircles(5, 10) flatMap { c2 =>
randomConcentricCircles(5, 10) map { c3 =>
c1 beside c2 beside c3
}
}
}
// programOneRewritten: Free[[A >: Nothing <: Any] => RandomOp[A], Image] = FlatMapped(
//   c = FlatMapped(
//     c = FlatMapped(
//       c = FlatMapped(
//         c = FlatMapped(
//           c = Suspend(a = RDouble),
//           f = cats.free.Free\$\$Lambda\$14283/0x0000000103cc6040@95e6970
//         ),
//         f = cats.free.Free\$\$Lambda\$14283/0x0000000103cc6040@5b352a1a
//       ),
//       f = cats.free.Free\$\$Lambda\$14283/0x0000000103cc6040@71ef0afa
//     ),
//     f = repl.MdocSession\$MdocApp5\$\$Lambda\$14300/0x0000000103cdd040@3ec001d5
//   ),
//   f = repl.MdocSession\$MdocApp5\$\$Lambda\$14303/0x0000000103cdb040@44affa94
// )``````

which makes it clearer that we're generating three different circles. </div>

#### Colored Boxes {-}

Let's return to a problem from the beginning of the book: drawing colored boxes. This time we're going to make the gradient a little more interesting, by making each color randomly chosen.

Recall the basic structural recursion for making a row of boxes

``````def rowOfBoxes(count: Int): Image =
count match {
case 0 => Image.rectangle(20, 20)
case n => Image.rectangle(20, 20).beside(rowOfBoxes(n-1))
}``````

Let's alter this, like with did with concentric circles, to have each box filled with a random color. Hint: you might find it useful to reuse some of the utilities we created for `randomConcentricCircles`. Example output is shown in Figure generative:random-color-boxes. <div class="solution"> This code uses exactly the same pattern as `randomConcentricCircles`.

``````val randomAngle: Random[Angle] =
Random.double.map(x => x.turns)
// randomAngle: Free[[A >: Nothing <: Any] => RandomOp[A], Angle] = FlatMapped(
//   c = Suspend(a = RDouble),
//   f = cats.free.Free\$\$Lambda\$14283/0x0000000103cc6040@36b86de1
// )

val randomColor: Random[Color] =
randomAngle.map(hue => Color.hsl(hue, 0.7, 0.7))
// randomColor: Free[[A >: Nothing <: Any] => RandomOp[A], Color] = FlatMapped(
//   c = FlatMapped(
//     c = Suspend(a = RDouble),
//     f = cats.free.Free\$\$Lambda\$14283/0x0000000103cc6040@36b86de1
//   ),
//   f = cats.free.Free\$\$Lambda\$14283/0x0000000103cc6040@3f890916
// )

def coloredRectangle(color: Color): Image =
Image.rectangle(20, 20).fillColor(color)

def randomColorBoxes(count: Int): Random[Image] =
count match {
case 0 => randomColor.map{ c => coloredRectangle(c) }
case n =>
val box = randomColor.map{ c => coloredRectangle(c) }
val boxes = randomColorBoxes(n-1)
box.flatMap{ b =>
boxes.map{ bs => b.beside(bs) }
}
}``````

</div>