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 指的是類別之間的對映,有點像實體或物件的函式。例如,我們有類別 A
和 B
以及將 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)
}
まとめ
在本文中,我們瞭解了提升的概念以及它在不同情況下的含義。以更可組合和更慣用的方式編寫程式碼非常有用,使我們能夠更多地關注程式碼的業務邏輯,而不是浪費時間構建程式碼的不同部分。