我经常发现在为每个实现做同样的事情之前我需要提取密封特征的类型:
sealed trait Trait
case class Foo() extends Trait
case class Bar() extends Trait
// ... lots of other implementations
// *must* take a `Trait`, not a `T <: Trait`
def thing(t: Trait): ??? = t match {
case f: Foo => // something with the instance and specific type
case b: Bar => // something with the instance and specific type
// ... same thing again for other implementations
}
Run Code Online (Sandbox Code Playgroud)
例如
// typically provided by somebody else...
trait Thing[T] { def thingy: String }
implicit def thing[T]: Thing[T] = new Thing[T] { def thingy = "stuff" }
def thing(t: Trait): String = t match {
case Foo() => implicitly[Thing[Foo]].thingy
case Bar() => implicitly[Thing[Bar]].thingy
// ...
}
Run Code Online (Sandbox Code Playgroud)
我想减少参与此操作的样板.
更新:现在我们将通过 shapeless 使用类型类派生。例如https://github.com/fommil/shapeless-for-mortals
事实证明,您可以使用 shapeless 的多态函数和余积来做到这一点:
object thing extends Poly1 {
implicit def action[T <: Trait: Thing] = at[T](
a => implicitly[Thing[T]].thingy
)
// magic that makes it work at the sealed trait level
def apply(t: Trait): String =
Generic[Trait].to(t).map(thing).unify
}
Run Code Online (Sandbox Code Playgroud)
然后可以像这样使用
println(thing(Foo(): Trait))
Run Code Online (Sandbox Code Playgroud)
我想通过抽象类更容易编写(让我们action暂时忘记传递隐式参数),例如
abstract class MatchSealed[In, Out] extends Poly1 {
implicit def poly[T <: In] = at[T](action)
def action[T <: In](t: T): Out
import ops.coproduct.Mapper
def apply[R <: HList](in: In)(
implicit
g: Generic.Aux[In, R],
m: Mapper[this.type, R]
): Out = {
val self: this.type = this
g.to(in).map(self).unify
}
}
Run Code Online (Sandbox Code Playgroud)
但这失败了,因为Mapper[self.type, g.Repr]最后一行丢失了。我不知道缺少哪个隐式,但我怀疑它是 self.type。我真的很想捕捉realisedSelf.type,但我不知道该怎么做。
更新:事实证明不可能获得,Mapper因为它需要访问已实现的object Unable to map on HList
| 归档时间: |
|
| 查看次数: |
288 次 |
| 最近记录: |