我正在尝试创建一个依赖于用户输入的类型类。想象一下,我们有一些案例对象:
sealed trait H
case object Ha extends H
case object Hb extends H
和类型类:
trait Foo[A] {
def bar: String
}
object Foo {
def bar[A : Foo] = implicitly[Foo[A]].bar
implicit object FooA extends Foo[Ha.type] {
override def bar: String = "A"
}
implicit object FooB extends Foo[Hb.type] {
override def bar: String = "B"
}
}
虽然我找到了一个使用匹配的工作解决方案:
variableComingFromMainArgs match {
case "a" => Foo.bar[Ha.type] _
case "b" => Foo.bar[Hb.type] _
}
我记得我们在Scala中有抽象类型,所以我可以将我的case类更改为:
sealed trait H {
type T <: H
}
case object Ha extends H {
type T = this.type
}
case object Hb extends H {
type T = this.type
}
现在,根据用户对程序的输入,我可以做类似的事情 val变量= Ha 的println(Foo.bar [variable.T])
然而,由于某些原因,这不起作用,而且错误对我来说不是很有用:
error: could not find implicit value for evidence parameter of type Foo[variable.T]
println(Foo.bar[variable.T])
任何想法,如果可以克服,如果没有,为什么?
感谢。
答案 0 :(得分:1)
Implicits是编译时构造,所以原则上它们不能直接依赖于用户输入(程序员可以像你一样使用模式匹配来连接它)。
请考虑以下代码。它按预期编译和工作:
trait H {
type A
}
case object Ha extends H {
override type A = Int
}
case object Hb extends H {
override type A = Long
}
trait Adder[T] {
def add(a: T, b: T): T
}
implicit object IntAdder extends Adder[Int] {
override def add(a: Int, b: Int): Int = a + b
}
implicit object LongAdder extends Adder[Long] {
override def add(a: Long, b: Long): Long = a + b
}
def addWithAdder(input: H)(a: input.A, b: input.A)(implicit ev: Adder[input.A]): input.A = ev.add(a, b)
val x: Int = addWithAdder(Ha)(3, 4)
val y: Long = addWithAdder(Hb)(3, 4)
让我们关注addWithAdder方法。由于路径依赖类型,编译器可以为此任务选择正确的隐式。但是这种方法基本上与以下相同:
def add[T](a: T, b: T)(implicit ev: Adder[T]) = ev.add(a, b)
第一个可以拥有的唯一优势是您可以自己提供所有实例并停止代码的用户添加自己的类型(当H
被密封并且所有实现都是最终的时)。