diff --git a/README.md b/README.md
index 873d0c85bb0a30dbb013fc481a5114a055090028..0efc9867441063c6dcff25492099004967eb3c4f 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,8 @@ usually marked with `???`.
 | 4: Laziness                     | [`laziness`](src/main/scala/laziness/)                            | `testOnly laziness.*`
 | 5: Algebras, Laws, and Monoids  | [`algebra`](src/main/scala/algebra/)                              | `testOnly algebra.*`
 | 6: Typeclasses                  | [`typeclasses`](src/main/scala/typeclasses/)                      | `testOnly typeclasses.*` (needs some uncommenting)
+| 7: Monads                       | [`monads`](src/main/scala/monads/)                                | `testOnly monads.*` (needs some uncommenting)
+| 8: Applicative Functors         | [`applicative`](src/main/scala/applicative/)                      | `testOnly applicative.*` (needs some uncommenting)
 
 ## Usage tips:
 To keep your local solutions to the exercises when pulling from the repository,
diff --git a/src/main/scala/applicative/Applicative.scala b/src/main/scala/applicative/Applicative.scala
new file mode 100644
index 0000000000000000000000000000000000000000..baf28032adb822c6b0d70e5d44f1f9e97e71af3e
--- /dev/null
+++ b/src/main/scala/applicative/Applicative.scala
@@ -0,0 +1,34 @@
+package applicative
+
+import scala.language.higherKinds
+
+trait Applicative[F[_]] {
+  def unit[A](a: A): F[A]
+
+  def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] = map2(ff, fa)((f, a) => f(a))
+
+  // implement map using unit and ap, but not flatMap/flatten
+  def map[A, B](fa: F[A])(f: A => B): F[B] = ???
+
+  // implement map2 using unit and ap
+  // hint: f.curried converts `(A,B) => C` to `A => (B => C)`
+  def map2[A, B, C](fa: F[A], fb: F[B])(f: (A, B) => C): F[C] = ???
+
+
+  // implement unit first
+  // then write the signature for ap and map2
+  // then implement one of them
+  def compose[G[_]](implicit G: Applicative[G]): Applicative[Lambda[a => F[G[a]]]] = {
+    val F = this
+    new Applicative[Lambda[a => F[G[a]]]] {
+
+      def unit[A](a: A): F[G[A]] = ???
+      //note: when you are done implementing this, the test for ap/map2 will result in a StackOverflow until you implement one of them
+
+
+      // override def ap... = ???
+      // or
+      // override def map2... = ???
+    }
+  }
+}
diff --git a/src/main/scala/applicative/Monad.scala b/src/main/scala/applicative/Monad.scala
new file mode 100644
index 0000000000000000000000000000000000000000..1455cae42461a088f7f524f3f731ff2c0cc178a1
--- /dev/null
+++ b/src/main/scala/applicative/Monad.scala
@@ -0,0 +1,11 @@
+package applicative
+
+import scala.language.higherKinds
+
+trait Monad[F[_]] extends Applicative[F] {
+  def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] = flatten(map(fa)(f))
+
+  def flatten[A](fa: F[F[A]]): F[A] = flatMap(fa)(identity)
+  override def map[A, B](fa: F[A])(f: A => B): F[B] = flatMap(fa)(f andThen unit)
+  override def map2[A, B, C](fa: F[A], fb: F[B])(f: (A, B) => C): F[C] = flatMap(fa)(a => map(fb)(b => f(a,b)))
+}
diff --git a/src/main/scala/applicative/Validated.scala b/src/main/scala/applicative/Validated.scala
new file mode 100644
index 0000000000000000000000000000000000000000..879f3735106a4f936f1c785382b24e9498794269
--- /dev/null
+++ b/src/main/scala/applicative/Validated.scala
@@ -0,0 +1,12 @@
+package applicative
+
+sealed trait Validated[+E, +A]
+case class Valid[+A](a:A) extends Validated[Nothing, A]
+case class Invalid[+E](head: E, tail: List[E] = List()) extends Validated[E, Nothing]
+
+object Validated {
+  implicit def validatedApplicative[E]: Applicative[Validated[E, +?]] = new Applicative[Validated[E,+?]] {
+    def unit[A](a: A) = Valid(a)
+    // add map2 or ap here
+  }
+}
diff --git a/src/test/scala/applicative/ApplicativeSpec.scala b/src/test/scala/applicative/ApplicativeSpec.scala
new file mode 100644
index 0000000000000000000000000000000000000000..58468199fd9bd6cf11c1c7b7ffe8c4aed2e83976
--- /dev/null
+++ b/src/test/scala/applicative/ApplicativeSpec.scala
@@ -0,0 +1,49 @@
+package applicative
+
+import org.scalatest._
+import testutil.PendingIfUnimplemented
+
+class ApplicativeSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
+  implicit val optionApplicative = new Applicative[Option] {
+    override def unit[A](a: A): Option[A] = Some(a)
+    override def ap[A, B](ff: Option[A => B])(fa: Option[A]): Option[B] = ff.flatMap(f => fa.map(f))
+  }
+  implicit val listApplicative = new Applicative[List] {
+    override def unit[A](a: A): List[A] = List(a)
+    override def ap[A, B](ff: List[A => B])(fa: List[A]): List[B] = ff.flatMap(f => fa.map(f))
+  }
+
+  "map" should "work the same when implemented via ap" in {
+    val f: Int => Int = i => i * 3
+    val g: String => String = s => "Hello " + s
+    val h: Int => String = _.toHexString
+
+    val someint = Some(2)
+    val somestring = Some("world")
+
+    optionApplicative.map(someint)(f) shouldBe someint.map(f)
+    optionApplicative.map(somestring)(g) shouldBe somestring.map(g)
+    optionApplicative.map(None)(g) shouldBe None.map(g)
+    optionApplicative.map(None)(g) shouldBe None.map(g)
+  }
+
+  "map2" should "combine two monadic values" in {
+    optionApplicative.map2(Some(1), Some(2))((a, b) => a + b) shouldBe Some(3)
+    optionApplicative.map2(Option.empty[Int], Some(2))((a, b) => a + b) shouldBe None
+    optionApplicative.map2(Some(2), Option.empty[Int])((a, b) => a + b) shouldBe None
+  }
+
+  "compose" should "create nested element with unit" in {
+    val ola: Applicative[Lambda[a => Option[List[a]]]] = optionApplicative.compose(listApplicative)
+
+    ola.unit(5) shouldBe Some(List(5))
+  }
+
+  it should "implement map2 or ap correctly" in {
+    val ola: Applicative[Lambda[a => Option[List[a]]]] = optionApplicative.compose(listApplicative)
+
+    val optList = Some(List(1, 2, 3, 4))
+
+    ola.map(optList)(_ + 10) shouldBe Some(List(11, 12, 13, 14))
+  }
+}
diff --git a/src/test/scala/applicative/ValidatedSpec.scala b/src/test/scala/applicative/ValidatedSpec.scala
new file mode 100644
index 0000000000000000000000000000000000000000..835cdcdff9254c9c2f595e2a963df0f902e443fc
--- /dev/null
+++ b/src/test/scala/applicative/ValidatedSpec.scala
@@ -0,0 +1,26 @@
+package applicative
+
+import org.scalatest._
+import testutil.PendingIfUnimplemented
+
+class ValidatedSpec extends FlatSpec with Matchers with AppendedClues with PendingIfUnimplemented {
+  "map2" should "accumulate errors" in {
+    type VSI = Validated[String, Int]
+    val valid1: VSI = Valid(1)
+    val valid2: VSI = Valid(2)
+    val invalidA: VSI = Invalid("A")
+    val invalidB: VSI = Invalid("B")
+    val invalidAB: VSI = Invalid("A", List("B"))
+    val invalidABAB: VSI = Invalid("A", List("B", "A", "B"))
+
+    val strErrorApplicative = implicitly[Applicative[Validated[String, +?]]]
+
+    ??? //remove, when you have overridden map2 or ap
+
+    strErrorApplicative.map2(valid1, valid2)((a, b) => a + b) shouldBe Valid(3)
+    strErrorApplicative.map2(invalidA, valid2)((a, b) => a + b) shouldBe invalidA
+    strErrorApplicative.map2(valid1, invalidB)((a, b) => a + b) shouldBe invalidB
+    strErrorApplicative.map2(invalidA, invalidB)((a, b) => a + b) shouldBe invalidAB
+    strErrorApplicative.map2(invalidAB, invalidAB)((a, b) => a + b) shouldBe invalidABAB
+  }
+}