Skip to content

Instantly share code, notes, and snippets.

@xuwei-k
Last active December 17, 2015 12:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xuwei-k/5611368 to your computer and use it in GitHub Desktop.
Save xuwei-k/5611368 to your computer and use it in GitHub Desktop.
Monad without map, flatMap, yield
scalaVersion := "2.11.6"
sealed trait Maybe[+A]
case class Just[+A](a: A) extends Maybe[A]
case object Not extends Maybe[Nothing]
sealed trait ConsList[+A]{
final def ::[AA >: A](h: AA): ConsList[AA] = Cons(h, this)
final def :::[AA >: A](h: ConsList[AA]): ConsList[AA] = {
def loop(other: ConsList[AA]): ConsList[AA] = other match{
case Cons(head, tail) => head :: loop(tail)
case NIL => this
}
loop(h)
}
}
final case class Cons[+A](private val head: A, private val tail: ConsList[A]) extends ConsList[A]
final case object NIL extends ConsList[Nothing]
trait Monad[F[_]]{
def point[A](a: A): F[A]
def bind[A, B](fa: F[A])(f: A => F[B]): F[B]
}
object Main extends App{
implicit val maybeMonad: Monad[Maybe] = new Monad[Maybe]{
def bind[A, B](fa: Maybe[A])(f: A => Maybe[B]) = fa match{
case Just(a) => f(a)
case Not => Not
}
def point[A](a: A) = Just(a)
}
implicit val listMonad: Monad[ConsList] = new Monad[ConsList]{
def bind[A, B](fa: ConsList[A])(f: A => ConsList[B]) = fa match{
case Cons(head, tail) => f(head) ::: bind(tail)(f)
case NIL => NIL
}
def point[A](a: A) = Cons(a, NIL)
}
implicit class MonadSyntax1[A](val a: A) extends AnyVal{
def point[F[_]: Monad]: F[A] = implicitly[Monad[F]].point(a)
}
implicit class MonadSyntax2[A, F[_]: Monad](val fa: F[A]){
def foreach[B](f: A => F[B]) = implicitly[Monad[F]].bind(fa)(f)
}
def not[A]: Maybe[A] = Not
val r1 = for{
a <- 1.point[Maybe]
b <- 2.point[Maybe]
c <- 3.point[Maybe]
} (a, b, c).point[Maybe]
assert(r1 == Just((1,2,3)))
val r2 = for{
a <- not[Int]
b <- 2.point[Maybe]
} (a, b).point[Maybe]
assert(r2 == Not)
val r3 = for{
a <- 1 :: 2 :: NIL
b <- 3 :: 4 :: NIL
} (a, b).point[ConsList]
assert(r3 == (1,3) :: (1,4) :: (2,3) :: (2,4) :: NIL)
val r4 = for{
a <- 1 :: 2 :: NIL
b <- NIL: ConsList[Int]
c <- 3 :: 4 :: NIL
} (a, b, c).point[ConsList]
assert(r4 == NIL)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment