# Lifting in Scala

- Transform Methods to Functions
- Transform Pure Functions to Functors in Scala
- Transform Partial Functions to Functions in Scala
- Monad Transformers in Scala
- Conclusion

This article will talk about lifting in the Scala programming language. Lifting has different meanings; it depends on the context we use it.

Let’s look at them one by one.

## Transform Methods to Functions

We sometimes encounter situations where we want to transform methods into functions. This is one example of lifting.

For example, let’s say we have the following methods:

```
def mul(x: Int) = x*5
def isEven(x: Int) = x%2==0
```

Now, we can compose these methods as below:

```
isEven(mul(4))
```

But what if we want this composition to happen in a functional way? Then we have to transform these above methods into functions.

That can be done by lifting them using the `_`

symbol in Scala.

```
val mulAns = mul _
val isEvenAns = isEven _
```

Now, we can functionally compose them as below:

```
( mulAns andThen isEvenAns)(5)
```

Full working code:

```
object MyClass {
def mul(x: Int) = x*5
def isEven(x: Int) = x%2==0
def main(args: Array[String])
{
println(isEven(mul(4)));
val mulAns = mul _
val isEvenAns = isEven _
println(( mulAns andThen isEvenAns)(5))
}
}
```

Output:

```
true
false
```

Explanation:

The first output is `true`

as 4 is multiplied by 5, which gives 20. This 20 is passed as a parameter to the `isEven`

function.

The second output is `false`

as 5 is multiplied by 5 first, and then its result is checked in the `isEven`

function.

## Transform Pure Functions to Functors in Scala

Functor refers to the mapping between categories, somewhat like a function of entities or objects. For instance, we have categories `A`

and `B`

and a functor `F`

that maps `A's`

objects to `B's`

objects.

```
trait Functor[F[_]] {
def mapping[A, B](X: F[A])(f: A => B): F[B]
def lifting[A, B](f: A => B): F[A] => F[B] =
X => map(X)(f)
}
```

In this context, lifting refers to taking a function from `A=>B`

and transforming it into a functor by making it a function of the form `F[A] => F[B]`

. When working with nested data types, this can be very useful.

## Transform Partial Functions to Functions in Scala

In this context, lifting refers to the extension of the domain. Partial functions are kinds of functions that can be applied to the subdomains of values.

But at times, we might want to extend their domain, and lifting helps us achieve that.

Let’s suppose we have a partial function that gives the square root of a positive number.

```
val sqrt: PartialFunction[Double, Double] =
{
case temp if temp >= 0 => Math.sqrt(temp)
}
```

Now, we can extend the domain of our partial function using the `lift`

method to make it look more elegant:

```
def getSqrtRootPartialFunction(t: Double) =
{
sqrt.lift(t).map(ans => s"Square root of ${t} is ${ans}")
.getOrElse(s"Cannot calculate square root for t")
}
```

Full working code:

```
object MyClass {
val sqrt: PartialFunction[Double, Double] = {
case temp if temp >= 0 => Math.sqrt(temp)
}
def getSqrtRootPartialFunction(t: Double) = {
sqrt.lift(t).map(ans => println(s"Square root of ${t} is ${ans}"))
.getOrElse(println(s"Cannot calculate square root for t"))
}
def main(args: Array[String])
{
getSqrtRootPartialFunction(35)
}
}
```

Output:

```
Square root of 35.0 is 5.916079783099616
```

Explanation:

So, what lifting of the `sqrt`

function has done here is that it extended the domain to whole double from `PartialFunction[Double, Double]`

to a `Function[Double, Option[Double]]`

.

Sometimes, lifting partial functions is used to avoid the `index out of bound`

exception.

```
Seq("1", "2", "3").lift(1) // Some("2")
Seq("1", "2", "3").lift(7) // none returned
```

The domain has been extended from `String`

to `Option[String]`

. So, when we try to access an out of bound value, the lifted `Seq`

returns `None`

instead of throwing an `out of bound`

exception.

## Monad Transformers in Scala

Combining monads together is done using monad transformers. Let’s say we have two `Futures`

:

```
val helloWorld: Future[Option[String]] = Future.successful(Some("hello world"))
val language: Future[String] = Future.successful("this is Scala language")
```

Now, as both the `Futures`

have different domains, we can use monad transformers by lifting `language`

to `OptionT`

. By this, we can handle the result in a more consistent way:

```
def MonadTransformer() = {
val message: OptionT[Future, String] = for {
hello <- OptionT(helloWorld)
name <- OptionT.liftF(language)
} yield println(s"$hello $name")
val result: Future[Option[String]] = message.value
Await.result(result, 1 second)
}
```

## Conclusion

In this article, we have learned the concept of lifting and what it means in different contexts. It is very useful to write our code in a more composable and idiomatic manner, allowing us to focus more on the business logic of the code rather than wasting time just building different parts of it.

**Suraj P**