[英]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.