Practical examples for Scala Cats in context of shopping cart

My experience trying to learn Functional Programming was painful. Reading blogs after blogs makes it more and more confusing. So I took the practical approach to learn and this is my effort to create a reference and make it easier for anyone who passes by my blog. As shopping cart is a common appl, I have used it as the basis for these examples

  • in FP we try to decouple data from behaviour
  • model your domain using ADT's(Algebraic Data Types)
    • Sum => choice or union using sealed abstract classes or trait
      eg:
          sealed abstract class CartStatus
          case object InProgress extends CartStatus
          case object Purchased extends CartStatus
          case object Dropped extends CartStatus
      
    • Product type => case class
      eg:composition saying we have a and b and c
      case class Checkout(
          item: Items,
          cartNumber: CartNumber)
      
  • Use type system to your advantage
    // anyval means value class. At runtime `AnyVal` gets removed only used during compile time for compile error
    

Option

import cats.syntax.option._ 
def someHttpCall(): Future {
    return futureResult
}
// the value is upcast to Option[T] from Some[T]

Cat 1: Functor

What: Functor is simply something that can be mapped over. In Scala map there is no concrete implementation of functor. But there is map which behaves like a functor.
When: When you need to map over a Option, List
Eg:

def getItemQuantity(item: Item, cart: Cart) {
    return cart[item].quantity
}
Functor[List].map(List("iphone9", "samsung"))(_.getItemQuantity)

Cat 2: Monoid

What: Monoid is simply a trait/class with combine and empty functionality that follows associative laws.

trait Monoid[A] {
    def combine(a: A, b: B): A
    def empty: A
}

Eg: Say you want to find the total number of items that makeup the shopping cart

def totalItems(items: List[Int]): Int = items.foldLeft(Monoid[Int].empty)(_ |+| _)

Cat 3: Type-safe Equality(Eq)

What: Cats support both === and =!= for equality and non-equality respectively
Eg: ```// custom equality
import cats.instances.long._
implicit val productEq: Eq(Product) =
Eq.instance[Product] {(product1, product2) =>
product1.name === product2.name
product1.sku === product2.sku
}