Учитывая класс типов, где выбор экземпляра должен быть выполнен на основе типа возвращаемого значения:Неожиданное неявное разрешение на основе умозаключения от обратного типа
case class Monoid[A](m0: A) // We only care about the zero here
implicit def s[T] : Monoid[Set[T]] = Monoid(Set.empty[T])
implicit def l[T] : Monoid[List[T]] = Monoid(List.empty[T])
def mzero[A](implicit m: Monoid[A]) : A = m.m0
почему Scala (2.11.6) не решить правильный экземпляр:
scala> mzero : List[Int]
<console>:24: error: ambiguous implicit values:
both method s of type [T]=> Monoid[Set[T]]
and method l of type [T]=> Monoid[List[T]]
match expected type Monoid[A]
mzero : List[Int]
^
, когда он не имеет никаких проблем с поиском неявное на основе типа возвращаемого при использовании функции неявно (переопределить его здесь, как я, чтобы проиллюстрировать, как S imilar это в mzero)
def i[A](implicit a : A) : A = a
scala> i : Monoid[List[Int]]
res18: Monoid[List[Int]] = Monoid(List())
Monoid[A]
, вместо Monoid[List[Int]]
в сообщении об ошибке озадачивает.
Я бы предположил, что многие разработчики сказаза знакомы с этой проблемой, поскольку, как представляется, это ограничивает удобство классов в scala.
РЕДАКТИРОВАТЬ: Я ищу, чтобы это работало без отклонения от типа. В противном случае я бы хотел понять, почему это невозможно. Если это ограничение документировано как проблема Scala, я не смог его найти.
Ограничения способности Scala использовать ожидаемые типы возвращаемых данных для указания вывода параметров типа при вовлечении имплицитов являются невероятно запутанными, поэтому все просто записывают 'mzero [List [Int]]'. –
Как некоторое обходное решение вы можете уйти, переопределив 'mzero' как' def mzero [A] (неявный m: Monoid [_ <: A]): A = m.m0'. Я бы сказал, что я бы пошел с 'mzero [List [Int]]', как упоминал Тревис Браун. –
Впечатляющий и удивительный. Благодаря! Любое объяснение? Кажется, это расслабляет тип и получает меньше матчей! –