[英]In Scala, what does “extends (A => B)” on a case class mean?
在研究如何在Scala中進行備忘時,我發現了一些我不喜歡的代碼。 我試圖查找這種特殊的“事物”,但是不知道用什么來稱呼它。 即引用它的術語。 此外,使用符號搜索也不容易!
我在這里看到了以下代碼可在Scala中進行記憶化:
case class Memo[A,B](f: A => B) extends (A => B) {
private val cache = mutable.Map.empty[A, B]
def apply(x: A) = cache getOrElseUpdate (x, f(x))
}
而extends (A => B)
部分正是使案例類擴展的東西。 首先,發生了什么事? 其次,為什么還需要它? 最后,您怎么稱這種繼承? 即是否可以使用一些特定的名稱或術語來指代它?
接下來,我看到這樣計算Fibanocci號碼使用備注這里 :
val fibonacci: Memo[Int, BigInt] = Memo {
case 0 => 0
case 1 => 1
case n => fibonacci(n-1) + fibonacci(n-2)
}
我可能沒有看到所有正在應用的“簡化”。 但是,我不知道val
行的結尾= Memo {
。 因此,如果更詳細地輸入,也許我會理解備忘錄的構造方式正在“飛躍”。
在這方面的任何幫助將不勝感激。 謝謝。
A => B
是Function1[A, B]
縮寫,因此您的Memo
將函數從A
擴展到B
,最明顯的是通過必須定義的apply(x: A): B
方法定義的。
由於使用了“中綴”符號,因此需要在類型周圍加上括號,即(A => B)
。 你也可以寫
case class Memo[A, B](f: A => B) extends Function1[A, B] ...
要么
case class Memo[A, B](f: Function1[A, B]) extends Function1[A, B] ...
為了完成0_的答案, fibonacci
通過Memo
的伴隨對象的apply方法實例化,由於Memo
是case類,因此編譯器會自動生成該對象。
這意味着將為您生成以下代碼:
object Memo {
def apply[A, B](f: A => B): Memo[A, B] = new Memo(f)
}
Scala對apply
方法有特殊的處理方式:調用它的名稱時不需要鍵入其名稱。 以下兩個調用嚴格等效:
Memo((a: Int) => a * 2)
Memo.apply((a: Int) => a * 2)
case
塊稱為模式匹配。 在引擎蓋下,它生成一個部分函數-即為其某些輸入參數(但不一定是所有輸入參數)定義的函數。 我不會詳細介紹局部函數(因為這很重要, 這是我就該主題寫給自己的備忘錄),但是從本質上講,這意味着case
塊實際上是PartialFunction的一個實例。
如果您PartialFunction
該鏈接,將會看到PartialFunction
擴展了Function1-這是Memo.apply
的預期參數。
因此,一旦刪除(如果是一個單詞),那段代碼實際上意味着的是:
lazy val fibonacci: Memo[Int, BigInt] = Memo.apply(new PartialFunction[Int, BigInt] {
override def apply(v: Int): Int =
if(v == 0) 0
else if(v == 1) 1
else fibonacci(v - 1) + fibonacci(v - 2)
override isDefinedAt(v: Int) = true
})
請注意,我已經大大簡化了模式匹配的處理方式,但我認為在開始討論關於unapply
和unapplySeq
是題外話和混亂。
我是以此方式進行記憶的原始作者。 您可以在同一文件中看到一些示例用法。 當您也想記住多個參數時,由於Scala展開元組的方式,它也非常有效:
/**
* @return memoized function to calculate C(n,r)
* see http://mathworld.wolfram.com/BinomialCoefficient.html
*/
val c: Memo[(Int, Int), BigInt] = Memo {
case (_, 0) => 1
case (n, r) if r > n/2 => c(n, n-r)
case (n, r) => c(n-1, r-1) + c(n-1, r)
}
// note how I can invoke a memoized function on multiple args too
val x = c(10, 3)
該答案是0__和Nicolas Rinaudo提供的部分答案的綜合。
摘要:
Scala編譯器有許多方便的假設(但也是如此)。
extends (A => B)
與extends Function1[A, B]
同義( Function1 [+ T1,-R]的ScalaDoc ) apply(x: A): B
的具體實現; def apply(x: A): B = cache.getOrElseUpdate(x, f(x))
match
的碼塊開頭= Memo {
{}
之間的內容作為參數傳遞給Memo case類構造函數 {}
之間為隱式類型,為PartialFunction[Int, BigInt]
,並且編譯器使用“ match”代碼塊作為PartialFunction方法的apply()
的替代,然后為PartialFunction的方法isDefinedAt()
提供其他替代isDefinedAt()
。 細節:
定義案例類Memo的第一個代碼塊可以這樣寫:
case class Memo[A,B](f: A => B) extends Function1[A, B] { //replaced (A => B) with what it's translated to mean by the Scala compiler
private val cache = mutable.Map.empty[A, B]
def apply(x: A): B = cache.getOrElseUpdate(x, f(x)) //concrete implementation of unimplemented method defined in parent class, Function1
}
可以更詳細地編寫定義val fibanocci的第二個代碼塊,如下所示:
lazy val fibonacci: Memo[Int, BigInt] = {
Memo.apply(
new PartialFunction[Int, BigInt] {
override def apply(x: Int): BigInt = {
x match {
case 0 => 0
case 1 => 1
case n => fibonacci(n-1) + fibonacci(n-2)
}
}
override def isDefinedAt(x: Int): Boolean = true
}
)
}
為了在行case n => fibonacci(n-1) + fibonacci(n-2)
處理自指問題,必須向第二個代碼塊的val添加lazy
。
最后,斐波那契的用法示例是:
val x:BigInt = fibonacci(20) //returns 6765 (almost instantly)
關於此extends (A => B)
一句話extends (A => B)
:這里的extends
不是必需的,但是如果要在更高階的函數或情況下使用Memo
的實例,則必須這樣做。
沒有這種extends (A => B)
,如果僅在方法調用中使用Memo
實例fibonacci
,那就完全可以了。
case class Memo[A,B](f: A => B) {
private val cache = scala.collection.mutable.Map.empty[A, B]
def apply(x: A):B = cache getOrElseUpdate (x, f(x))
}
val fibonacci: Memo[Int, BigInt] = Memo {
case 0 => 0
case 1 => 1
case n => fibonacci(n-1) + fibonacci(n-2)
}
例如:
Scala> fibonacci(30)
res1: BigInt = 832040
但是,當您想在高階函數中使用它時,會出現類型不匹配錯誤。
Scala> Range(1, 10).map(fibonacci)
<console>:11: error: type mismatch;
found : Memo[Int,BigInt]
required: Int => ?
Range(1, 10).map(fibonacci)
^
因此,這里的extends
僅有助於將實例fibonacci
標識給其他實例,因為它具有apply
方法,因此可以完成一些工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.