Разница между Ad-hoc полиморфизмом и параметрическим полиморфизмом в 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.") 
    }
}

(Не уверен, что это фактическая реализация головы, но это не имеет значения)

С другой стороны, классы типов считаются adhoc-полиморфизмом. Так как мы можем предоставить различные реализации, привязанные к типам.

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

В середине у нас есть методы, такие как фильтр, которые параметризованы, но мы можем предоставить различные реализации, предоставляя различные функции.

List(1,2,3).filter(_ % 2 == 0)
// List(2)

Являются ли такие методы, как фильтр, карта и т. Д., Специальным полиморфизмом? Почему или почему нет?

1 ответ

Решение

Метод filter на Lists является примером параметрического полиморфизма. Подпись

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]]

Поэтому, я думаю, можно сказать, что это своего рода "гибридный параметрический-специальный полиморфизм", который сначала пытается найти наиболее подходящий класс специального типа. CanBuildFrom[List[A], B, That] в неявном объеме, но в конечном итоге возвращается к обычному параметрическому полиморфизму и возвращает универсальный подход CanBuildFrom[List[A], B, List[B]]решение, которое является параметрически полиморфным в обоих A а также B,

См. Следующую презентацию для отличного введения в специальный полиморфизм в Scala: https://www.slideshare.net/pjschwarz/ad-hoc-polymorphism-using-type-classes-and-cats