If F has a functor instance available, it's possible to lift any function A => B to F[A] => F[B].
If F has an applicative functor instance available, it's possible to lift any function A => B => C => .. => Z to F[A] => F[B] => F[C] => .. => F[Z]. Essentially, applicative functor is a generalization of functor for arbitrary arity.
You can learn about functor and applicative functors here and here. There is also this excellent talk which covers these ideas.
Scalaz library provides these abstractions (and more!).
import scalaz._ import Scalaz._ scala> val foo: Int => String = _.toString foo: Int => String = <function1> scala> foo.lift[Option] res0: Option[Int] => Option[String] = <function1> scala> res0(Some(3)) res1: Option[String] = Some(3) scala> res0(None) res2: Option[String] = None scala> val add: (Int, Int) => Int = _ + _ add: (Int, Int) => Int = <function2> scala> add.lift[Option] res3: (Option[Int], Option[Int]) => Option[Int] = <function2> scala> res3(Some(2), Some(1)) res4: Option[Int] = Some(3) scala> res3(Some(2), None) res5: Option[Int] = None scala> res3(None, None) res6: Option[Int] = None
Scalaz pimps lift method on Function2, Function3 etc because curried functions being syntactially heavier are used less often. Behind the scenes, the lifting happens with Function1s (i.e. curried functions).
You might also want to take a look at Scalaz source code.