Mic*_*ael 5 scala typeclass shapeless
假设我有一个ADT和类型类,Foo
如下所示:
sealed trait A
case class A1() extends A
case class A2() extends A
case class A3() extends A
trait Foo[X] { def foo(x: X): String; }
object Foo {
implicit val a1foo = new Foo[A1] { def foo(a1: A1) = "A1" }
implicit val a2foo = new Foo[A2] { def foo(a2: A2) = "A2" }
implicit val a3foo = new Foo[A3] { def foo(a3: A3) = "A3" }
}
Run Code Online (Sandbox Code Playgroud)
现在我可以这样写Foo[A]
:
implicit val afoo = new Foo[A] {
def foo(a: A) = a match {
case a1 : A1 => a1foo.foo(a1)
case a2 : A2 => a2foo.foo(a2)
case a3 : A3 => a3foo.foo(a3)
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,这段代码太过于热衷.是否有可能摆脱所有样板并自动导出 Foo[A]
(可能与shapeless
)?
这种afoo
隐式不仅在其他三个存在的情况下毫无用处,甚至很糟糕,因为它会因值MatchError
上的值而失败new A {}
。
我不明白为什么Foo[A]
当您拥有涵盖类型的所有可能(有效)值A
并且afoo
不添加任何内容的隐式时,您需要这样的实例。
我可以想象如果你有一个函数
def foo(a: A)(implicit f: Foo[A]): String = f.foo(a)
Run Code Online (Sandbox Code Playgroud)
那么,当然, 、a1foo
或a2foo
都不a3foo
适合。afoo
会,所以foo(A1())
会编译并正常工作,但foo(new A {})
也会编译,并因MatchError
. 顺便说一句,如果foo(new A {})
代码中存在该调用,它将在编译时发出有关非详尽匹配的警告,但如果不是,它将静默编译。
所以解决这个问题的方法是修改foo
, 采用更精确的类型:
def foo[X <: A](a: X)(implicit f: Foo[X]): String = f.foo(a)
Run Code Online (Sandbox Code Playgroud)
现在foo(A1())
将编译并选择(与anda1foo
相同),而只是不会编译(因为它不应该)。A2
A3
foo(new A {})
如果您仍然希望有一个实例Foo[A]
作为默认情况,您可以像这样更改代码:
object Foo extends Foo_1 {
implicit val a1foo: Foo[A1] = ...
implicit val a2foo: Foo[A2] = ...
implicit val a3foo: Foo[A3] = ...
}
trait Foo_1 {
// this implicit has a lower priority:
implicit val afoo: Foo[A] = new Foo[A] { def foo(a: A) = "A" }
}
Run Code Online (Sandbox Code Playgroud)
现在foo(new A {})
或foo(A2(): A)
将编译并返回"A"
。
PS顺便说一句,建议编写显式类型的隐式。
归档时间: |
|
查看次数: |
228 次 |
最近记录: |