无形记录类型可以用作 Poly1 吗? - 第2部分
Can shapeless Record type be used as a Poly1? - Part 2
因为我没有从第 1 部分得到答案:
我假设此功能在 shapeless 中不存在。所以我决定自己的命运,自己写一个:
import shapeless.record._
case class GetV[H <: HList](hh: H) extends Poly1 {
implicit def getter[S](
implicit
ev: Selector[H, S]
): Case.Aux[S, ev.Out] = at[S] { s =>
val w = Witness(s)
val _ev = ev.asInstanceOf[Selector[H, w.T]]
val v = hh.apply(w)(_ev)
v.asInstanceOf[ev.Out]
}
}
它按预期工作,唯一的问题是 asInstanceOf
的 2 次调用,我认为这是一种不安全的 hack,可以规避 typechecker 在单例类型上的陷阱。应该如何改进?
如果你想知道它的性能,这是我的测试代码:
import shapeless.syntax.singleton._
val record = ("a" ->> 1) ::
("b" ->> "x") ::
HNil
it("getV") {
object get extends RecordUtils.GetV(record)
assert(get.apply("a".narrow) == 1)
assert(get("b".narrow) == "x")
}
更新 1:这只是我观察到的所有问题之一,如果我将测试用例更改为等效的东西:
it("getV") {
// object get extends RecordUtils.GetV(record) <----- should be the same
val get = RecordUtils.GetV(record)
assert(get.apply("a".narrow) == 1)
assert(get("b".narrow) == "x")
}
它破坏了编译:
[Error] .../RecordUtilsSpec.scala:19: could not find implicit value for parameter cse: shapeless.poly.Case[get.type,String("a") :: shapeless.HNil]
[Error] .../RecordUtilsSpec.scala:20: could not find implicit value for parameter cse: shapeless.poly.Case[get.type,String("b") :: shapeless.HNil]
two errors found
2个测试用例有什么区别? val/object 是否获得了两个不稳定路径以便它们的依赖类型具有本地作用域?
请参阅我对第 1 部分的回答。
关于第 2 部分,您可以使用类型 class 作为隐式参数(而不是扩展方法和 Witness
)
case class GetV[H <: HList](hh: H) extends Poly1 {
implicit def getter[S](implicit
ev: Selector[H, S]
): Case.Aux[S, ev.Out] = at[S] { _ =>
ev(hh)
}
}
关于更新,在 Shapeless 中常见的情况是多态函数应该通过对象而不是 val
s 来定义。否则你必须导入 implicits
val get = GetV(record)
import get._
因为我没有从第 1 部分得到答案:
我假设此功能在 shapeless 中不存在。所以我决定自己的命运,自己写一个:
import shapeless.record._
case class GetV[H <: HList](hh: H) extends Poly1 {
implicit def getter[S](
implicit
ev: Selector[H, S]
): Case.Aux[S, ev.Out] = at[S] { s =>
val w = Witness(s)
val _ev = ev.asInstanceOf[Selector[H, w.T]]
val v = hh.apply(w)(_ev)
v.asInstanceOf[ev.Out]
}
}
它按预期工作,唯一的问题是 asInstanceOf
的 2 次调用,我认为这是一种不安全的 hack,可以规避 typechecker 在单例类型上的陷阱。应该如何改进?
如果你想知道它的性能,这是我的测试代码:
import shapeless.syntax.singleton._
val record = ("a" ->> 1) ::
("b" ->> "x") ::
HNil
it("getV") {
object get extends RecordUtils.GetV(record)
assert(get.apply("a".narrow) == 1)
assert(get("b".narrow) == "x")
}
更新 1:这只是我观察到的所有问题之一,如果我将测试用例更改为等效的东西:
it("getV") {
// object get extends RecordUtils.GetV(record) <----- should be the same
val get = RecordUtils.GetV(record)
assert(get.apply("a".narrow) == 1)
assert(get("b".narrow) == "x")
}
它破坏了编译:
[Error] .../RecordUtilsSpec.scala:19: could not find implicit value for parameter cse: shapeless.poly.Case[get.type,String("a") :: shapeless.HNil]
[Error] .../RecordUtilsSpec.scala:20: could not find implicit value for parameter cse: shapeless.poly.Case[get.type,String("b") :: shapeless.HNil]
two errors found
2个测试用例有什么区别? val/object 是否获得了两个不稳定路径以便它们的依赖类型具有本地作用域?
请参阅我对第 1 部分的回答。
关于第 2 部分,您可以使用类型 class 作为隐式参数(而不是扩展方法和 Witness
)
case class GetV[H <: HList](hh: H) extends Poly1 {
implicit def getter[S](implicit
ev: Selector[H, S]
): Case.Aux[S, ev.Out] = at[S] { _ =>
ev(hh)
}
}
关于更新,在 Shapeless 中常见的情况是多态函数应该通过对象而不是 val
s 来定义。否则你必须导入 implicits
val get = GetV(record)
import get._