Practical examples for Scala Cats in context of shopping cart

Page content

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 }