thomas legrand
thomas legrand

Reputation: 493

why can I use map on a function here?

I don't understand why this code compiles :

def lift[A,B](f: A => B): Option[A] => Option[B] = _ map f

If I do :

val f: Int => Double = _.toDouble

Then lift(f) works fine, but f map f gives an error : error: value map is not a member of Int => Double

Upvotes: 1

Views: 68

Answers (2)

slouc
slouc

Reputation: 9698

I don't understand why this code compiles :

def lift[A,B](f: A => B): Option[A] => Option[B] = _ map f

It's short for

def lift[A,B](f: A => B): Option[A] => Option[B] = (o: Option[A]) => o map f 

Method lift returns a function that:
- takes an Option[A]
- modifies that option's contents using some function f: A => B
- returns the result, Option[B]

So, when you "lift" some function f: A => B, you basically upgrade it from A => B to Option[A] => Option[B]. When this new upgraded function is given o: Option[A], it will map that option's content into Option[B] (by using f: A => B which was provided when original function was being upgraded).

If I do:

val f: Int => Double = _.toDouble

Then lift(f) works fine, but f map f gives an error error: value map is > not a member of Int => Double

Yes, because you cannot map over a function. You can only map over something by using a function (by the way, things you can map over are called functors).

What you want to do is:

  1. Define some function f (you defined val f: Int => Double = _.toDouble)
  2. Use lift to "upgrade" you function f from Int => Double to Option[Int] => Option[Double]
  3. Use your new upgraded function to map over an Option[Int], thereby transforming it into an Option[Double].

So:

val f: Int => Double = _.toDouble
val upgraded = lift(f)
println(upgraded(Some(8))) // prints Some(8.0)

Upvotes: 2

codejitsu
codejitsu

Reputation: 3182

The lift function simply lifts your function f: A=> B to the function on some other domain, in this case it is Option[_]. So, your implementation of lift gives you a function f': Option[A] => Option[B], and because Option has the map function, you can call it on the first input parameter (this is the 'underscore').

You don't have to call f map f. What you do is lifting your f function:

val f: Int => Double = _.toDouble
val lifted = lift(f)
lifted(Some(42)) //it should be Some(42.0)

Upvotes: 1

Related Questions