Do you think IIT Guwahati certified course can help you in your career?
No
Introduction
Hello Ninjas, this blog aims to provide you with a guide for understanding scala as a programming language and then knowing about the monad in scala. Starting from its basics, we will learn how to use it and how it condenses codes and improves their overall quality and readability.
So let us begin our journey of exploring monad in scala by knowing what Scala is.
Scala is a general-purpose programming language. It combines functional and object-oriented programming in one concise. It was designed to overcome the shortcomings of java and make it better. It runs on JVM (Java Virtual Machine) and requires java bytecode for compilation.
A monad is a design pattern in functional programming that represents a computation or sequence of computations as a data type. It provides a way to encapsulate and compose operations that involve side effects or context, such as I/O, error handling, or state manipulation, in a pure and composable manner.
In simpler terms, a monad is a container that wraps a value or computation along with additional context or behavior. It defines two main operations: "unit" (also known as "return" or "pure"), which wraps a value into the monadic context, and "bind" (also known as "flatMap" or "chain"), which applies a function to the value inside the monad, producing a new monad.
Comparison of Scala with other popular programming languages
On comparing Scala with other programming languages like Java and C++, we get to know that in scala, we don’t think in terms of instructions like we do in others listed above. We believe in terms of values and compose these values to obtain new values. In scala, everything is an expression that can be unit type reduced to a value.
In scala, we don’t use loops or iterations; we use recursion. It has variables, loops, and iterations, but they are heavily discouraged in scala.
What is Monad in scala?
Monads in scala are containers that contain some elements. Monads don’t allow us to operate on them directly; instead, they have their properties. So, when we do operations with containers, they work within themselves using these properties. Monad is helpful because it condenses the code, serving its primary purpose. Monads are deeply related to the mathematics part of computer science, precisely from the part of category theory. So, in other words, monad in scala is a way of sequencing computations to make the code concise. In scala, the contents of these containers are defined in terms of types so that they can be any valid scala type.
The properties that monads possess are:
A parametrized type
Unit
FlatMap
A parametrized type
Monad in scala requires a parametrized type. One such type can be Option. The type Option defines a type parameter as Option[T]. It is the simplest possible monad in scala that contains either one or zero elements.
Unit
It is like a wrapper function used to wrap values inside the monad. It is defined as T => M[T], for example, Int => Option[Int]. It does not return any data types, like the void function of Java and C++. In scala, the Unit is the apply method; it is a method that is not required to be named. T.apply() is the same as T().
FlatMap
It acts like a mechanism to sequence the computations on the values wrapped inside the monad. We can define it as (M[A], A => M[B]) => M[B]. We can understand this equation as first lifting an A inside an M. Then taking a function that lifts and converts A to B inside M. Then, combining the two to get a B inside an M.
Examples of collection supporting map as well as flatMap
In Scala, collections that support both map and flatMap operations are typically monadic collections. These collections allow for mapping over their elements and also flattening nested collections into a single collection. Here are some examples:
1. List:
map: Applies a function to each element of the list, returning a new list of the results.
flatMap: Similar to map, but the function returns a collection for each element, and flatMap flattens these collections into a single list.
val list = List(1, 2, 3) val mappedList = list.map(_ * 2) // [2, 4, 6] val flatMappedList = list.val list = List(1, 2, 3)
val mappedList = list.map(_ * 2) // [2, 4, 6]
val flatMappedList = list.flatMap(x => List(x, x * 2)) // [1, 2, 2, 4, 3, 6](x => List(x, x * 2)) // [1, 2, 2, 4, 3, 6]
2. Option:
map: Applies a function to the value inside the Option, returning a new Option with the result.
flatMap: Similar to map, but the function returns an Option, and flatMap flattens nested Options into a single Option.
val option = Some(5)
val mappedOption = option.map(_ * 2) // Some(10)
val flatMappedOption = option.flatMap(x => Some(x * 2)) // Some(10)
3. Future:
map: Applies a function to the value inside the Future, returning a new Future with the result.
flatMap: Similar to map, but the function returns a Future, and flatMap flattens nested Futures into a single Future.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
val future = Future(7)
val mappedFuture = future.map(_ * 2) // Future(14)
val flatMappedFuture = future.flatMap(x => Future(x * 2)) // Future(14)
Map, a special case of FlatMap
We can define a map as M[A] => M[B]. It is used when a function is like A => B and not like A => M[B].
From the above explanation of FlatMap, we understood that FlatMap has two functions applying a function to A and flattening a nested container. But when the function does not lift A, flattening is not required, so we just use the function. This is not the case with the map. This is the main difference between Map and FlatMap. For example,
Explanation: A lifting function Unit will wrap the objects inside it, even if that object is the same as the type of container. So to avoid this, adding of extra wrapper FlatMap is used.
For the assurance that the application of functions unit and flatMap in any sequence will lead to a valid monad, the monad has to comply with three laws. Those three laws of a monad are
Left Identity
Right Identity
Associativity
Left identity
According to the left identity, “applying a function f using the flatMap function to a value x lifted by the unit function is equivalent to applying the function f directly to the value x.”
Monad.unit(x).flatMap(f) = f(x)
You can also try this code with Online Java Compiler
According to the law of associativity, “applying two functions f and g to a monad value using a sequence of flatMap calls is equivalent to applying g to the result of the application of the flatMap function using f as the parameter.”
A monad is used to encapsulate computations with side effects or context, providing a way to sequence and compose operations in a pure and predictable manner.
What is the main benefit of using monad in Scala?
The main benefit of using a monad in scala is it helps us in composing functions. It is the main reason why we use monad in scala. The code becomes easier to read and debug for errors by composing functions and condensing them.
Which property of a monad has the function of wrapping values in a monad?
Unit is the property of a monad which is used as a wrapper function to wrap values inside a monad.
How many laws are there of the monad in scala?
There are three laws of the monad in Scala, and it is a must that all three are followed to guarantee that any sequence of functions(unit and flatMap) will give a valid monad. The laws are left identity, right identity, and associativity.
Conclusion
In this article, we read about the monad in scala. We started by knowing Scala as a programming language, then we moved forward to monad in scala, saw its properties, and learned about the laws it has to follow.
We hope that this blog was helpful to you and helped you increase your knowledge of monad in scala and its advantages and uses. For more about Scala, refer What is Scala? To learn more about JVM and JDK, visit JVM and Its architecture and Java Development Kit(JDK), respectively.