# Exercise

``````git checkout day-1-step-0

sbt compile test

# go to advent/solutions/Day1.scala and fix the tests``````
`Code a functional solution to Part 1`

# Solutions

``git diff day-1-step-0 day-1-step-1``
``````
def fuel(mass: Int): Int =
(mass / 3) - 2

def calculateFuels(masses: List[Int]): List[Int] =
masses.map(fuel)

def sumFuels(fuels: List[Boolean]): Int =
fuels.sum

def sumOfFuel(masses: List[Boolean]): Int =
sumFuels(calculateFuels(masses))
``````

# Abstraction

``def weLikeCats: Boolean = ???``
``def weLikeCats(b: Boolean): Boolean = ???``
``def weLikeCats[A](a: A): A = ???``
``def weLikeCats(b: Boolean): Boolean = ???``

# Exercise

``````git checkout day-1-step-1-abstraction

sbt compile test

# go to advent/solutions/Abstraction.scala and fix the tests``````
`Complete the Abstraction exercises`
``````  def fold[A, B](o: Option[A], f: A => B, b: B): B = {
o match {
case None    => b
case Some(v) => f(v)
}
}
``````
``````def list[A]: List[A] = Nil
``````
``````def fuel[A](mass: A): A = {
(mass / 3) - 2
}
``````
``````def fuel[A](mass: A)
(quotient: (A, A) => A,
minus: (A, A) => A,
two: A,
three: A): A = {
minus(quotient(mass, three), two)
}
``````
``fuel(12)(_ / _, _ - _, 2, 3)``
``````trait Mass[A] {
def quotient(a: A, b: A): A
def minus(a: A, b: A): A
def two: A
def three: A
}
``````
``````def fuel[A](mass: A)(M: Mass[A]): A =
M.minus(M.quotient(mass, M.three), M.two)``````
``````val intHasMass: Mass[Int] = new Mass[Int] {
def quotient(a: Int, b: Int): Int = a / b
def minus(a: Int, b: Int): Int = a - b
def two: Int = 2
def three: Int = 3
}``````
``fuel[Int](12)(intHasMass)``
``def fuel[A](mass: A)(implicit M: Mass[A]): A``
``````implicit val intHasMass: Mass[Int] =
new Mass[Int] {
// code
}``````
``fuel(12)``

# Exercise

``````# peek at the solution if you need to
git diff day-1-step-1 day-1-step-2``````
`Create a Mass typeclass and use it in the fuel function`

# Semigroup

``((a combine b) combine c) should be (a combine (b combine c))``
``````trait Semigroup[A] {
def combine(a: A, b: A): A
}``````

# Monoid

``````(a combine empty) should be(empty combine a)

(a combine empty) should be(a)``````
``````trait Monoid[A] extends Semigroup[A] {
def empty: A
}``````
``````import cats._
import cats.implicits._``````
``````def sumFuels[A](fuels: List[A])
(implicit M: Monoid[A]): A = ???``````

# Exercise

``git checkout day-1-step-2``
`Use a monoid for sumFuels and sumOfFuel`

# Solution

``git diff day-1-step-2 day-1-step-3``

# Exercise

``````git checkout day-1-step-3

sbt compile test

# go to advent/solutions/Day1.scala and fix the tests``````
`Code a functional solution to Part 2`

# Solution

``git diff day-1-step-3 day-1-step-4``

# Order

``````trait Order[A] {
def eqv(a: A, b: A): Boolean
def compare(a: A, b: A): Int
}``````
``a < b``

# Exercise

``git checkout day-1-step-4``
`Use Monoid and Order in Part 2`

# Solution

``git diff day-1-step-4 day-1-step-5``

# Functor

``````fa.map(f).map(g) should be fa.map(f.andThen(g))
``````
``````trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
``````
``````fa.map(x => x) = fa
``````

# Foldable

``````trait Foldable[F[_]] {
def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B
}
``````

# Exercise

``git checkout day-1-step-5``
`Use Functor and Foldable in Part 1`

# Solution

``git diff day-1-step-5 day-1-step-6``

By Zainab Ali

• 554