Chapter 9

  1. Implement Monad[Try].
implicit val tryMonad = new Monad[Try] {
override def unit[A](a: => A): Try[A] = Success(a)

override def flatMap[A, B](a: Try[A])(f: A => Try[B]): Try[B] = a match {
case Success(value) => f(value)
case Failure(ex) => Failure(ex)
}
}
  1. Prove the right identity law for the State monad.

Let's start with the property definition we had in this chapter:

val rightIdentity = forAll { (a: A, f: A => M[B]) =>
M.flatMap(M.unit(a))(f) == f(a)
}

Let f(a) = a => State(s => (b, s2))

First, we substitute the definition of unit with the result of the call. Hence, M.flatMap(M.unit(a))(f) becomes M.flatMap(State(s => (a, s)))(f).

Next, we substitute M.flatMap with compose, which gives us State(s => (a, s)).compose(f).

Next, we'll use the lemma proved in this chapter to substitute the compose call with the definition of it:

State(s => { 
val
(a, nextState) = (a, s)
f(a).run(nextState)
}

By application of f, the previous code can be simplified to State(s => State(s => (b, s2)).run(s) and further to State(s => (b, s2)(1)

The right side of the equation, f(a), is by definition equal to State(s => (b, s2))(2)

We have (1) == (2) and hence proved the right identity law for the state monad.

  1. Pick one of the monads we defined in this chapter and implement the go function that will encode the notion of sinking the boat with a 1% probability.

Option will represent the notion of the sunk boat: 

import Monad.optionMonad

def go(speed: Float, time: Float)(boat: Boat): Option[Boat] =
if (Random.nextInt(100) == 0) None
else Option(boat.go(speed, time))

println(move(go, turn[Option])(Option(boat)))
  1. Please do the same but encode the notion of a motor breaking in 1% of the moves, leaving the boat immobilized.

Both Try and right-biased Either can be used to encode the case of the broken motor. 

Following is the implementation with Try:

import Monad.tryMonad

def go(speed: Float, time: Float)(boat: Boat): Try[Boat] =
if (Random.nextInt(100) == 0) Failure(new Exception("Motor malfunction"))
else Success(boat.go(speed, time))

println(move(go, turn[Try])(Success(boat)))

Following is the implementation with Either:

import Monad.eitherMonad
type ErrorOr[B] = Either[String, B]

def go(speed: Float, time: Float)(boat: Boat): ErrorOr[Boat] =
if (Random.nextInt(100) == 0) Left("Motor malfunction")
else Right(boat.go(speed, time))

println(move(go, turn[ErrorOr])(Right(boat)))
  1. Describe the essence of monads we defined in this chapter using (loosely) the following template: The state monad passes state between chained computation. The computation itself accepts the outcome of the previous calculation and returns the result along with the new state.

The option monad allows the chaining of computations which might return no result. The computations are carried over until the last one or until the first one returns no result. 

The try monad does the same as the option monad but instead of having a special no result value, which aborts the whole computation chain, it has a notion of failure represented by a Failure case class.

Either monad has similar semantics to the option and try monads but, in this case, the notion of aborting the sequence of steps is carried on by the Left type and the notion of continuing the sequence, by the Right type.

  1. Define a go method that both tracks the boat's position and takes the possibility of sinking the boat using the structure with the following type: type WriterOption[B] = Writer[Vector[(Double, Double)], Option[Boat]].
object WriterOptionExample extends App {
type WriterOption[B] = Writer[Vector[(Double, Double)], Option[B]]
import WriterExample.vectorMonoid

// this implementation delegates to the logic we've implemented in the chapter
def go(speed: Float, time: Float)(boat: Boat): WriterOption[Boat] = {
val b: Option[Boat] = OptionExample.go(speed, time)(boat)
val c: WriterTracking[Boat] = WriterExample.go(speed, time)(boat)
Writer((b, c.run._2))
}

// constructor - basically unit for the combined monad
private def writerOption[A](a: A) =
Writer[Vector[(Double, Double)], Option[A]](Option(a))

// we need a monad of the appropriate type
implicit val readerWriterMonad = new Monad[WriterOption] {
override def flatMap[A, B](wr: WriterOption[A])(f: A => WriterOption[B]): WriterOption[B] =
wr.compose {
case Some(a) => f(a)
case None => Writer(Option.empty[B])
}

override def unit[A](a: => A): WriterOption[A] = writerOption(a)
}
// tracks boat movement until it is done navigating or sank
println(move(go, turn)(writerOption(boat)).run)
}
  1. Compare the answer to Question 6 and the way we combined applications in the previous chapter.

In Chapter 8Dealing with Effects, we implemented a generic combinator for applications. In this implementation involving monads, we needed to know how to dissect the options effect in order to be able to implement the combination logic. Please read Chapter 10A Look at Monad Transformers and Free Monad, for more details.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.19.174