In the context of functional programming, the terms “effects” and “effectful” are largely used. However, it is difficult to find a definition of what they are. This is because there is no specific definition for it. Fortunately, I recently got an opportunity to learn and explore effects in more detail. So this blog is an attempt to describe these terms in the context of functional programming. But before describing effects, let’s get back to a closely related concept – Monads.
What are Monads?
In the simplest sense, monads are the wrappers that provide some additional feature to the enclosed value. Metaphorically, monads are containers that augment an object or value.
Consider a scenario where you want to gift one hundred chocolates to your friend. It is impractical to carry them loosely. So you decide to put them in a box, wrap the box and gift it to your friend.
In this scenario, the box has provided you with the ability to efficiently carry and gift wrap the chocolates. This is exactly what a monad does in the programming world. In Scala, the List[T]
is used to hold similar data types together and easily perform computations on each element using map
and flatMap
methods. In fact, in Scala a monad is any class that implements the map
and flatMap
methods. Implementing these methods allows the instances to be chained in for-expressions.
What are Effects?
It is important to mention in the beginning that here we are not talking about the side effects. We are rather talking about the main effects. Effect is what a monad handles or the main purpose of each monad is its respective effect.
For example, one of the features of Scala is to handle the nullability of an object by wrapping it inside Option[T]
. So for a monad, Option[T]
the effect is providing optionality to an object or value.
For more examples of monad and their respective effect, consider the table below:
Monad | Effect |
Future[T] | Provides the effect of latency |
Try[T] | Provides the effect of managing exceptions |
Functional Effect:
While effect can be considered as an operation, functional effect is the description of that operation. In other words, effect is about doing something and functional effect is about the description of doing something. Technically, functional effect is more about turning the computations to first-class values. For example Scala code:
println(“Hello, World!”)
is an effect that prints “Hello, World!” to the console. However, the ZIO code:
Console.printLine(“Hello, World!”)
is a functional effect of printing the same message to the console. It is the description of such an operation.
How Effects Provide Edge to Programs?
In pure functional programming, the functions should be effectful.
Consider a scenario where a developer needs to write a code to parse numeric String to Integer type.
def parseToInt(s:String): Int = {
try {
Integer.parseInt(s.trim)
} catch {
case e: Exception => ???
}
}
In the approach shown above, if s is non-parsable, there are two choices with the programmer-
- Return 0 (but it would not distinguish if the input was “0” or something non-parsable like “foo”)
- Return
null
(Bad practice in FP and OOP)
Monad types can easily address and solve this problem. Consider the code snippet below-
def parseToInt(s:String): Option[Int] = {
try {
Some(Integer.parseInt(s.trim))
} catch {
case e: Exception => None
}
}
This function uses the monad Option[Int]
to handle the problem described above. If the parsing is successful, the output holds Some(value)
else, it holds None
. Clearly, the return type of the function is- Option[Int]
, instead of Int
. Such functions are called effectful functions. Instead of returning A
, effectful functions return F[A]
. In other words, effectful functions return a monad. Such functions are more robust and provide an edge to the program.