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:
How can we use semigroups by using Scala?
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.
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
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:
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.
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:
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.
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:
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:
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:
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:
- 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.
- 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.
- and more…