Специальный полиморфизм - типовые классы
Я посмотрел учебник по скалазу.
По этой ссылке я понимаю следующий код:
scala> def sum[A](xs: List[A])(implicit m: Monoid[A]): A = xs.foldLeft(m.mzero)(m.mappend)
sum: [A](xs: List[A])(implicit m: Monoid[A])A
scala> implicit val intMonoid = IntMonoid
intMonoid: IntMonoid.type = IntMonoid$@3387dfac
scala> sum(List(1, 2, 3, 4))
res9: Int = 10
Но я не понимаю следующий код:
scala> def sum[A: Monoid](xs: List[A]): A = {
val m = implicitly[Monoid[A]]
xs.foldLeft(m.mzero)(m.mappend)
}
sum: [A](xs: List[A])(implicit evidence$1: Monoid[A])A
scala> sum(List(1, 2, 3, 4))
res10: Int = 10
Если мы рассмотрим List(1, 2, 3, 4)
, A
является Int
,
Так как мы можем иметь A
Monoid
а также A
Int
в def sum[A: Monoid](xs: List[A]): A = {
?
Спасибо
1 ответ
Синтаксис A : X
называется "привязанным к контексту", и это эквивалентно получению неявного параметра типа X[A]
, То есть следующие два объявления одинаковы:
def sum[A: Monoid](xs: List[A]): A
def sum[A](xs: List[A])(implicit $ev0: Monoid[A]): A
Однако имя неявного параметра недоступно при использовании границ контекста, поэтому вам нужно "извлечь" его, если вам нужно использовать его напрямую. Одним из способов сделать это является использование implicitly
метод, как видно:
val m = implicitly[Monoid[A]]
Вот определение implicitly
:
def implicitly[T](implicit v: T): T = v
Во всяком случае, два определения, которые вы показали, в значительной степени совпадают. Если вы понимаете первый, просто знайте, что второй идентичен, но написан с другим синтаксисом.
Последнее замечание о границах контекста: может показаться глупым использовать синтаксис привязки контекста только для использования implicitly
впоследствии, чтобы получить имя параметра. Но если вам просто нужно, чтобы неявный параметр передавался как неявный для других методов - и, следовательно, вам не нужно знать имя - это делает объявления намного более аккуратными.