Search code examples
scalafunctional-programmingliftingoption-type

When and why to Lift a Function


Consider this code:

def f1(a: Int, b: Int) = a + b

def f2(a: Option[Int], b: Option[Int]): Int = (a, b) match {
  case (Some(x), Some(y)) => x + y
  case _ => throw new IllegalArgumentException
}

println(f1(10, 20))
println(f2(Some(10), Some(20)))

I heard you can "lift" f1 to be like f2. As a beginner I have the following question:

What is lifting and why it used? In terms of implementation, how can I "lift" f1?

Any explanation is greatly appreciated as it is a bit tricky to find why I would "lift" something


Solution

  • Why: when you have a function with signature like f1 and want to "call it" on Option[Int]s (or List[Int]s, etc)

    How: you could write it directly:

    def lift2option[A, B, C](f: (A, B) => C): (Option[A], Option[B]) => Option[C] = ???
    

    I'm leaving it undefined because you should try writing it yourself; your definition of f2 should be a good starting point. Note that I made it return Option[Int] instead of Int. Later I can edit and give the answer if you want.

    And then instead of defining f2 as separate function, you do:

    val f2 = lift2option(f1 _)
    println(f2(Some(10), Some(20)))
    

    Of course, the point is that now for any function with a signature like f1 you can get an f2 equivalent.

    It can be further generalized to work not only for Option, but you'll want to look into that later.