### Higher Kinded type

A higher-kinded type which is also called a type constructor describes types that require a type to be a concrete type.

An example is the Option data type:

```
val something: Option = ??? // not a valid type
val otherthing : Option[Int] = ??? // valid type
```

Same goes for list, futures e.t.c

### Functors

A functor captures the notion of something you can map over, changing its

“contents” (or output) but not the structure itself.

The type signature of map on higher kinded types F[A] is:

def mapB : F[B]

### Applicatives

An applicative functor, also known as applicative, is a functor that can transform

multiple structures, not just one.

Imagine, we have a number of Option[Int] and we want to perform some sort of operation all of them in a functional manner, we could do that

using a for loop:

```
val opt1 = Option(1)
val opt2 = Option(2)
val opt3 = Option(3)
val result = for {
a <- opt1
b <- opt2
c <- opt3
} yield a + b + c
```

But with an applicative functor, we can combine the operations using one of the `mapN`

methods.

`val result = (opt1,opt2,opt3).mapN((a,b,c) => a + b + c)`

or simply

`val result = (opt1,opt2,opt3).mapN(_ + _ +_ )`

We’ve done the same thing with less lines of code. The applicative functor has enabled us to combine multiple F[A]

### Monads

A monad is a mechanism for sequencing computations: this computation happens after that computation. Roughly speaking, a monad provides a flatMap method for a context F[A]:

`def flatMap[B](f: A => F[B]): F[B]`

The for comprehension as well know is just syntactic sugar for nested flatMap calls

Effects can be composed using the `flatMap`

method.