## Accelerators

### Go to Overview

KDP KDSP

#### TechHub

Akka Scala Rust Spark Functional Java Kafka Flink ML/AI DevOps Data Warehouse

# ScalaFP: Understanding Semigroups In Scala Pragmatically

Reading Time: 3 minutes

In our previous post, we discussed semigroups according to mathematics and we conclude that semigroups have two properties called closure and associativity. But still, we have some questions like:

2. ### Where do we require to use semigroups?

First, let’s try to figure out, when and where we require semigroups in our code and during this we will automatically figure out, how can we use semigroups as well. First of all, we have an example which is divided into steps and during this example, we are going to explore semigroups pragmatically.

### Pre-requisite:

 case class Money(dollars: Int, cents: Int) trait Data { val balance = Money(102, 44) val salary = Money(320, 0) val balances: Map[String, Money] = Map( "James" –> Money(212, 98), "Jimmy" –> Money(43, 44) ) val salaries: Map[String, Money] = Map( "James" –> Money(500, 98), "Jimmy" –> Money(500, 44) ) val marbles: Map[String, Int] = Map( "James" –> 4, "Jimmy" –> 5 ) val won: Map[String, Int] = Map( "James" –> 2, "Jimmy" –> 1 ) }

view raw
Semigroups1.scala
hosted with ❤ by GitHub

### Step1:

We have class Money which contains states called dollars and cents. We know, the behavior of money is that, it can either be added or subtracted. For that, we need to create a method called `add` .

 //add money function def addMoney(money1: Money, money2: Money): Money = { Money(money1.dollars + money2.dollars + ((money1.cents + money2.cents) / 100), (money1.cents + money2.cents) % 100) }

view raw
Semigroups2.scala
hosted with ❤ by GitHub

### Step2:

Now we have `add` method for money, but what if we require to add Ints, Floats or even Maps? For this, we need to create separate methods for each:

 // add any two integer value def addInt(a: Int, b: Int): Int = a + b // add employe salary to their account balances def addMoneyMap(balances: Map[String, Money], salary: Map[String, Money]): Map[String, Money] = { balances.foldLeft(salaries){ case (acc, (name, money)) => acc + (name –> acc.get(name).map(addMoney(_ , money)).getOrElse(money)) } }

view raw
Semigroups3.scala
hosted with ❤ by GitHub

### Step3:

Now, we have three methods, addMoney, addInt, and addMap. But all of the methods perform the same binary operation. So, if we require a generic method for all, How can  we do that?

Scala provides a beautiful feature called traits. We need to create one trait and create an abstract method called `add` in the trait.

 // generic trait addable trait Addable[T] { def add(a: T, b: T): T }

view raw
Semigroups4.scala
hosted with ❤ by GitHub

### Step4:

Now, we have a common trait which contains an abstract method called `add` and we are pretty much familiar, according to our requirement we can implement add method based on our required types like Int, Float, Money, Map and more.

So, before moving into the type implementations for the `add `method, we will be creating another method, which creates an abstraction between implementation and performs an operation according to passed types as below:

view raw
Semigroups5.scala
hosted with ❤ by GitHub

In this snippet, we are doing nothing, just using only another beautiful feature of Scala called implicit and execute the method `add` in Addable type.

### Step5:

Now, let’s create an implementation of Addable type `add` method according to our requirements. Currently, we require to implement add method, for Int, Money and Map types. So we code as below:

view raw
Semigroups6.scala
hosted with ❤ by GitHub

### Step6:

Now, if we call the add method, which interacts with the user and create an abstract layer, so according to passed type the method executes the implementation and gives us a result. The whole code of the example is as below:

view raw
Semigroups7.scala
hosted with ❤ by GitHub

# But still, In the whole example where are semigroups???

So, if you remember, one of the properties in semigroups is closure. Where we perform some operation on 2 elements of set and answer belongs to the same set. If we look into the Addable `add` method, which performs some operation on the basis of type and returns the same type, that exactly is called semigroup.

Semigroups in functional programming contain only one method called `combine`, which combines the same type elements and return the same type of results. In the above example, we need to write a lot of custom code but Scala has a beautiful library called scala-cats, which contains predefined interface called Semigroup and that interface contains a method called combine. So, we need to implement `combine` method according to our type but scala-cats provide a lot of predefined implementations of combine method according to predefined types like Int, Double, Map, List and more.

Now we need to refactor above example according to scala-cats  as below:

 object Example4Semigroup extends App with Data { implicit val moneySemigroup = new Semigroup[Money] { override def combine(x: Money, y: Money): Money = { Money(x.dollars + y.dollars + ((x.cents + y.cents) / 100), (x.cents + y.cents) % 100) } } import cats.instances.int._ import cats.instances.map._ def add[A: Semigroup](a: A, b: A)(implicit semigroup: Semigroup[A]): A = semigroup.combine(a, b) println(s"Salary credit in you account xxxxxxx \${add(balance, salary)}") println(s"Salary transfer to all employees \${add(balances, salaries)}") // another way to call combine method with beautiful syntax using cats import cats.syntax.semigroup._ println(s"Salary transfer to all employees \${balances |+| salaries}") println(s"Your game marbles balance is: \${marbles |+| won}") } // output // Salary credit in you account xxxxxxx Money(422,44) // Salary transfer to all employees Map(James -> Money(713,96), Jimmy -> Money(543,88)) // Salary transfer to all employees Map(James -> Money(713,96), Jimmy -> Money(543,88)) // Your game marbles balance is: Map(James -> 6, Jimmy -> 6)

view raw
Semigroups8.scala
hosted with ❤ by GitHub

The whole examples are picked from this blog. They have explained semigroups is an easy manner with real-life examples and I really love it. Following are some real-life scenarios where semigroups come into the picture:

1. Domain Modeling: While you design your model according to your business domain, you should identify, your domain has a property like a combine or not.
2. Combine multiple logs parallelly: As we know, semigroups also support the associative property, that means, we can easily distribute our implementation between multiple clusters of gather logs and at last, combine them all.
3. and more…

### References:

#### Written by Harmeet Singh(Taara)

Harmeet Singh is a lead consultant, with experience of more than 5 years. He has expertise in Scala, Java, JVM, and functional programming. On a personal front; he is a food lover.