A monad M is a parametric type M[T] with two operations flatMap and unit that have to satisfy some laws.
trait M[T] {
  def flatMap[U](f: T => M[U]): M[U]
}
def unit[T](x: T): M[T]- List is a monad with unit(x) = List(x)
- Set is monad with unit(x) = Set(x)
- Option is a monad with unit(x) = Some(x)
- Generator is a monad with unit(x) = single(x)
flatMap is an operation on each of these types, whereas unit in Scala is different for each monad.
map can be defined for every monad as a combination of flatMap and unit:
m map f == m flatMap (x => unit(f(x)))
        == m flatMap (f andThen unit)To qualify as a monad, a type has to satisfy three law:
- Associativity:
m flatMap f flatMap g == f flatMap (x => f(x) flatMap g)- Left unit:
unit(x) flatMap f == f(x)- Right unit:
m flatMap unit == mIn the later parts of this course we will need a type named Try.
Try resembles Option, but instead of Some/None there is a Success case with a value and Failure case that contains an exception:
abstract class Try[+T]
case class Success[T](x: T)       extends Try[T]
case class Failure(ex: Exception) extends Try[Nothing]Try is used to pass results of computations that can fail with an exception between threads and computers
You can wrap up an arbitrary computation in a Try
Try(expr)  // gives Success(someValue) or Failure(someException)Here's an implementation of Try:
object Try {
  def apply[T](expr: => T): Try[T] =
    try Success(expr)
    catch {
      case NonFatal(ex) => Failure(ex)
    }Just like with Option, Try-valued computations can be composed in for expressions.
for {
  x <- computeX
  y <- computeY
} yield f(x, y)If computeX and computeY succeed with result Success(x) and Success(y) this will return Success(f(x,y)) If either computation fails with an exception ex, this will return Failure(ex).
abstract class Try[T] {
  def flatMap[U](f: T => Try[U]): Try[U] = this match {
    case Success(x) => try f(x) catch { case NonFatal(ex) => Failure(ex) }
    case fail: Failure => fail
  }
  
  def map[U](f: T => U): Try[U] = this match {
    case Success(x) => Try(f(x))
    case fail: Failure => fail
  }}So for a Try value t,
t map f == t flatMap (x => Try(f(x)))
        == t flatMap (f andThen Try)