Scala 类型类和子类型

Scala 类型类和子类型,scala,typeclass,implicit,subtyping,Scala,Typeclass,Implicit,Subtyping,我有以下定义类型类的代码 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)

我有以下定义类型类的代码

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(newa,newb)
我得到的是
List(“A”,“A”)
而不是
List(“A”,“B”)
。对于类型为
B
的类,如何确保使用
BtoFoo
方法而不是
AToFoo

隐式解析纯粹是一种编译时机制。这里区分子类型的简单方法是在隐式中进行匹配。完全删除
BtoFoo
,并使用
>一个
版本处理这两种情况

implicit val AIsFoo : Foo[A] = toFoo { 
  case b: B => "B"
  case a: A => "A"
}
当然,也可以为层次结构的一部分委托给方法。您可以在
a
中委托给方法,在
B
中委托给方法,并且仍然具有用于列表的typeclass工作,在这里您不能添加方法


你也可以考虑声明<代码> Fo< <代码>反变量.< /p>你期望什么类型的代码>清单(新的A,新的B)<代码>?我希望代码>列表(new a,new b)< /c> >类型<代码>列表[a] < /COD>在这种情况下,当你映射<代码> ToFoO< <代码> > <代码>列表[A] < /代码>时,它显然最先执行<代码> [Fo[a] ]并获取

AToFoo
隐式定义,并将其用于每个元素。TypeClass是为类型定向分派而设计的,而不是为值定向分派而设计的,因此它们并不总是能很好地处理子类型。我已经使用模式匹配实现了您的建议,但在我看来,检查所有子类型似乎不是很优雅在
AIsFoo
A
的ren,而不是能够直接为A的任何孩子
X
编写
XIsFoo
。声明
Foo
逆变如何工作?我尝试了
trait Foo[-T]{def toFoo(X:T):String}