---
# System prepended metadata

title: Untitled

---

Implement a minimal `Option` that has `map` and `flatMap`.
```scala
import scala.{Option => _}
// implement here

/*
class Functor f where
    fmap :: f a -> (a -> b) -> f b

class Monad f where
    return :: a -> f a
    ma flatMap f :: m a -> (a -> m b) -> m b

instance Functor Option where

    fmap f None = None
    fmap f (Some a) = Some (f a)

instance Monad Option where

    return = Some

    None flatMap f = None
    Some(x) flatMap f = f x

*/


fold f a xs = 

sealed trait Option[+A]{
   
    def map[B](f: A => B): Option[B] = {
        this match {
            case None => None
            case Some(x) => Some(f(x))
        }
    }    
    
    def flatMap[B](f: A => Option[B]): Option[B] = {
        this match {
            case None => None
            case Some(x) => f(x)
        }
    }
    
    def fold[B]( b: => B, f: A => B ): B = 
        this match {
            case None => b
            case Some(a) => f(a)
        }
    
    
    def map2[B](f: A => B): Option[B] = {
        
        this fold ( None, a => Some(f(a)) )

    }


// OptionIsFunctor: (Functor(Some(_))) 

case class Some[A](a: A) extends Option[A] 

case object None extends Option[Nothing]


val x: Option[Int] = Some(10)
val y: Option[Int] = None

Some(10).fold("Its empty", _.toString) // "11"
None.fold("Its empty", _.toString) // "Its empty"


Some(10).fold(calculateNthPrime(99999999999), _ + 1) // 11

sealed trait Animal
case class Cat() extends Animal

val a: Option[Animal] = Some(Cat()): Some[Cat]
val b: Option[Animal] = None
val c: Option[Cat]    = None




