У меня есть следующий код, определяющий класс типа.Typeclasses и подтипирование
trait Foo[T] {
def toFoo(x: T): String
}
trait Foos {
def toFoo[T](f: T => String): Foo[T] = new Foo[T] {
def toFoo(x: T): String = f(x)
}
}
object Foo extends Foos {
def toFoo[A: Foo](a: A) = implicitly[Foo[A]].toFoo(a)
implicit def AToFoo: Foo[A] = toFoo { c =>
"A"
}
implicit def BToFoo[T]: Foo[B] = toFoo { c =>
"B"
}
implicit def ListToFoo[T: Foo]: Foo[List[T]] = toFoo { c =>
c.map(toFoo(_)).
}
}
class A
class B extends A
Теперь, если у меня есть, если я toFoo(List(new A, new B)
я получаю List("A", "A")
вместо List("A", "B")
. Как я могу убедиться, что используется метод BtoFoo
, а не AToFoo
для классов с типом B
?
Какой тип вы ожидаете? Список (новый A, новый B) 'есть? –
Я ожидаю, что 'List (new A, new B)' будет иметь тип 'List [A]' – Stephan
в этом случае, когда вы сопоставляете 'toFoo' над' List [A] ', он, по-видимому, сначала выполняет' неявно [Foo [A]] 'и получает' AToFoo' неявный def и использует его для каждого элемента. Typeclasses предназначены для отправки по типу, а не для ориентированной на стоимость отправки, поэтому они не всегда хорошо играют с подтипированием. –