Scala 中 Ad-hoc 多态性和参数多态性的区别
Difference between Ad-hoc polymorphism and Parametric polymorphism in Scala
所以,我一直在搜索有关 parametric polymorphism
和 adhoc-polymorphism
之间主要区别的文档,但我仍然有一些疑问。
例如,像集合中的 head
这样的方法,显然是参数多态性,因为用于获取 List[Int] 中的头部的代码与任何其他 List 中的相同。
List[T] {
def head: T = this match {
case x :: xs => x
case Nil => throw new RuntimeException("Head of empty List.")
}
}
(不确定这是否是 head 的实际实现,但没关系)
另一方面,类型 类 被认为是临时多态性。由于我们可以提供不同的实现,因此受限于类型。
trait Expression[T] {
def evaluate(expr: T): Int
}
object ExpressionEvaluator {
def evaluate[T: Expression](value: T): Int = implicitly[Expression[T]].evaluate(value)
}
implicit val intExpression: Expression[Int] = new Expression[Int] {
override def evaluate(expr: Int): Int = expr
}
ExpressionEvaluator.evaluate(5)
// 5
在中间,我们有像 filter 这样的参数化方法,但是我们可以通过提供不同的功能来提供不同的实现。
List(1,2,3).filter(_ % 2 == 0)
// List(2)
filter、map 等方法是否被视为临时多态性?为什么或为什么不?
List
上的方法 filter
是参数多态性的一个例子。签名是
def filter(p: (A) ⇒ Boolean): List[A]
它对所有类型的工作方式完全相同A
。由于可以参数化任意类型A
,所以是普通的参数化多态
像map
这样的方法同时使用了这两种类型的多态性。
map
的完整签名是:
final def map[B, That]
(f: (A) ⇒ B)
(implicit bf: CanBuildFrom[List[A], B, That])
: That
此方法依赖于隐式值(CBF-gizmo)的存在,因此它是临时多态性。然而,一些提供正确类型的 CBF 的隐式方法实际上本身在 A
和 B
类型中是参数多态的。因此,除非编译器设法在隐式作用域中找到一些非常特殊的临时构造,例如 CanBuildFrom[List[String], Int, BitSet]
,否则它迟早会退回到
之类的东西
implicit def ahComeOnGiveUpAndJustBuildAList[A, B]
: CanBuildFrom[List[A], B, List[B]]
因此,我认为可以说这是一种 "hybrid parametric-ad-hoc polymorphism" 首先尝试在隐式范围内找到最合适的临时类型 class CanBuildFrom[List[A], B, That]
,但最终又回到了普通的参数多态,returns 一个万能的 CanBuildFrom[List[A], B, List[B]]
解决方案,在 A
和 B
.[=26= 中都是参数多态的]
所以,我一直在搜索有关 parametric polymorphism
和 adhoc-polymorphism
之间主要区别的文档,但我仍然有一些疑问。
例如,像集合中的 head
这样的方法,显然是参数多态性,因为用于获取 List[Int] 中的头部的代码与任何其他 List 中的相同。
List[T] {
def head: T = this match {
case x :: xs => x
case Nil => throw new RuntimeException("Head of empty List.")
}
}
(不确定这是否是 head 的实际实现,但没关系)
另一方面,类型 类 被认为是临时多态性。由于我们可以提供不同的实现,因此受限于类型。
trait Expression[T] {
def evaluate(expr: T): Int
}
object ExpressionEvaluator {
def evaluate[T: Expression](value: T): Int = implicitly[Expression[T]].evaluate(value)
}
implicit val intExpression: Expression[Int] = new Expression[Int] {
override def evaluate(expr: Int): Int = expr
}
ExpressionEvaluator.evaluate(5)
// 5
在中间,我们有像 filter 这样的参数化方法,但是我们可以通过提供不同的功能来提供不同的实现。
List(1,2,3).filter(_ % 2 == 0)
// List(2)
filter、map 等方法是否被视为临时多态性?为什么或为什么不?
List
上的方法 filter
是参数多态性的一个例子。签名是
def filter(p: (A) ⇒ Boolean): List[A]
它对所有类型的工作方式完全相同A
。由于可以参数化任意类型A
,所以是普通的参数化多态
像map
这样的方法同时使用了这两种类型的多态性。
map
的完整签名是:
final def map[B, That]
(f: (A) ⇒ B)
(implicit bf: CanBuildFrom[List[A], B, That])
: That
此方法依赖于隐式值(CBF-gizmo)的存在,因此它是临时多态性。然而,一些提供正确类型的 CBF 的隐式方法实际上本身在 A
和 B
类型中是参数多态的。因此,除非编译器设法在隐式作用域中找到一些非常特殊的临时构造,例如 CanBuildFrom[List[String], Int, BitSet]
,否则它迟早会退回到
implicit def ahComeOnGiveUpAndJustBuildAList[A, B]
: CanBuildFrom[List[A], B, List[B]]
因此,我认为可以说这是一种 "hybrid parametric-ad-hoc polymorphism" 首先尝试在隐式范围内找到最合适的临时类型 class CanBuildFrom[List[A], B, That]
,但最终又回到了普通的参数多态,returns 一个万能的 CanBuildFrom[List[A], B, List[B]]
解决方案,在 A
和 B
.[=26= 中都是参数多态的]