Scala 中的 Lift

Suraj P 2023年1月30日
  1. 将方法转换为函数
  2. 在 Scala 中将纯函数转换为向量
  3. 在 Scala 中把部分函数转化为函数
  4. Scala 中的 Monad 变形金刚
  5. 结论
Scala 中的 Lift

本文将讨论 Scala 编程语言中的提升。提升有不同的含义;这取决于我们使用它的上下文。

让我们一一看看。

将方法转换为函数

我们有时会遇到想要将方法转换为函数的情况。这是 Lift 的一个例子。

例如,假设我们有以下方法:

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

现在,我们可以组合这些方法如下:

isEven(mul(4))

但如果我们想让这种组合以函数的方式发生呢?那么我们就必须将上述方法转化为函数。

这可以通过使用 Scala 中的 _ 符号来提升它们来完成。

val mulAns = mul _
val isEvenAns = isEven _

现在,我们可以在功能上组合它们如下:

( mulAns andThen isEvenAns)(5)

完整的工作代码:

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))
    }
}

输出:

true
false

解释:

第一个输出是 true,因为 4 乘以 5,得到 20。这个 20 作为参数传递给 isEven 函数。

第二个输出是 false,因为首先将 5 乘以 5,然后在 isEven 函数中检查其结果。

在 Scala 中将纯函数转换为向量

Functor 指的是类别之间的映射,有点像实体或对象的函数。例如,我们有类别 AB 以及将 A's 对象映射到 B's 对象的函子 F

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)
}

在这种情况下,提升是指从 A=>B 中获取一个函数并将其转换为函子,使其成为 F[A] => F[B] 形式的函数。在使用嵌套数据类型时,这非常有用。

在 Scala 中把部分函数转化为函数

在这种情况下,提升是指域的扩展。偏函数是可以应用于值的子域的函数。

但有时,我们可能想要扩展他们的领域,而提升帮助我们实现了这一目标。

假设我们有一个偏函数,它给出一个正数的平方根。

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

现在,我们可以使用 lift 方法扩展部分函数的域,使其看起来更优雅:

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

完整的工作代码:

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)
    }
}

输出:

Square root of 35.0 is 5.916079783099616

解释:

所以,这里对 sqrt 函数的提升所做的是将域从 PartialFunction[Double, Double] 扩展到 Function[Double, Option[Double]] 的整个双精度域。

有时,提升部分函数用于避免 index out of bound 异常。

Seq("1", "2", "3").lift(1) // Some("2")

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

域已从 String 扩展到 Option[String]。因此,当我们尝试访问超出范围的值时,提升的 Seq 返回 None 而不是抛出 out of bound 异常。

Scala 中的 Monad 变形金刚

将 monad 组合在一起是使用 monad 转换器完成的。假设我们有两个 Futures

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

现在,由于两个 Futures 具有不同的域,我们可以通过将 language 提升到 OptionT 来使用 monad 转换器。这样,我们可以以更一致的方式处理结果:

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)
}

结论

在本文中,我们了解了提升的概念以及它在不同情况下的含义。以更可组合和更惯用的方式编写代码非常有用,使我们能够更多地关注代码的业务逻辑,而不是浪费时间构建代码的不同部分。

作者: Suraj P
Suraj P avatar Suraj P avatar

A technophile and a Big Data developer by passion. Loves developing advance C++ and Java applications in free time works as SME at Chegg where I help students with there doubts and assignments in the field of Computer Science.

LinkedIn GitHub