Scala tutorials
Functional Design Principles In Scala: Functors, Monad and Monoids
Scala is a functional programming language and each functional programming language should follow functional design principles. In this article we will briefly see a few key design principles and their examples.
Functors In Scala
Functor is a FP principal maps two different data types(categories). Scala has functor type implementations but actual functor implementations can be found in libraries like cats etc.
Below are some features of Functor-
 – It provides facility to wrap and unwrap things(categories)
 – It provides two functionalities, one to do mapping and another wrapping.
 – It follows identify and associativity rules.
 – It has a map() function and a unit() function (can be named anything inside)
 – Is all about applying functionalities on data inside a CONTEXT which are allowed by context.
 – It is a type class.
 – it defines how a map will be applied to data.
Syntax:
map :(A=>B) => F[A]=>F[B]
Example of Functor:
object FunctorsExample { case class MyContainer[A](things: A) { def map[B](fn: (A) => B): MyContainer[B] = { //Custom Functor MyContainer(fn(things)) } } val doubleThings = (data: Int) =>data*2 def main(args: Array[String]): Unit = { val mythings = MyContainer(100) val result = mythings.map(data => doubleThings(data)) println(result) } }
Output
MyContainer(200)
Monad In Scala
Monad is FP principal in Scala, it is used to provide mapping between two types(categories).
Key points to be noted for Monad
        – Monad is a FP principle which is used for mapping between two types/categories.
        – It is used to create structure to hold things inside and facilitate them.
        – It is a type class
        – On top of the functor it has flatMap() and flatten() functions.
Scala List or Maps don’t have any specific monad implementations but they have feature line monad, map, flatMap() and flatten(), so we can say they somewhat follow Monad FP.
Example Of Monad
See in below example Monad has map() like Functor but also has flatten and flatMap() to take out things if they are wrapped twice.
object MonadExamples { def main(args: Array[String]): Unit = { //Custom Monads case class MyContainer[A](things: A) { def map[B](fn: (A) => B): MyContainer[B] = MyContainer(fn(things)) def flatten = things def flatMap[B](fn: (A) => MyContainer[B]): MyContainer[B] = fn(things) } //Using Monads val mythings = MyContainer(100) //In this case by using map we can unwrap, transform things, but things of Monad are still in wrap so we use flatten() and flatMap() to take them out. val tripleThings = (data: Int) => MyContainer(data * 3) //So here we wont get container of container as flatten will flat it println(mythings.map(tripleThings).flatten) println(mythings.flatMap(tripleThings)) } }
Output
MyContainer(MyContainer(300))
MyContainer(300)
MyContainer(300)
Monoids In Scala
Monoids are another FP design principle to implement your data types of Monoid. Monoid provides a feature to do binary operation on two inputs and also defines identity/empty/zero element method.
Features and important points related to Monoids
 -Monaid is type together with associativity binary (op) which has an identity element(0),
  – Monoid is a small FP data structure.
  – Monoid is a type class.
  – It is used to perform algebraic calculations on individual elements
  – It is a ADT (algebraic data type)
  – It also belongs to category theory with one single object in category
  – It is used to build complex systems/computations by combining small operations.
  – They allow to perform single binary operation
In below example we can see so many Monoids implemented and used:
Example:
object MonoidsExample { //Monoid data structure or type class trait Monoid[T] { //should have identity rule and identity element def empty : T // name can be identity, empty, zero element def combine(arg1: T, arg2: T): T // can be add, op, combine etc. } //Example Int addition monoid val indAdditionMonoid = new Monoid[Int] { override def empty: Int = 0 override def combine(arg1: Int, arg2: Int): Int = arg1+arg2 } implicit val indAdditionMonoid1 = new Monoid[Int] { override def empty: Int = 0 override def combine(arg1: Int, arg2: Int): Int = arg1+arg2 } val intMethodMonoid = new Monoid[Int=>Int] { override def empty : Int=>Int = (arg:Int) => arg override def combine(arg1: Int=>Int, arg2: Int=>Int) = arg1 andThen arg2 } def combineAll(listInt : List[Int]) (monoid: Monoid[Int] ): Int = { listInt.fold(monoid.empty)((accumalator, data) => monoid.combine(accumalator,data)) } def main(args: Array[String]): Unit = { println(indAdditionMonoid.empty) println(indAdditionMonoid.combine(3,4)) println(intMethodMonoid.combine((data:Int) => data*2, (data:Int) => data*3)) println(combineAll(List(1,2,3))(indAdditionMonoid)) } }
Output
0
7
scala.Function1$$Lambda$7/901506536@2c8d66b2
6
 There are other design principles as well but above mentioned are the most used ones in any FP language.
 Reference
 Next Article
- Scala Interview Questions