shapeless Record 类型可以用作 Poly1 吗?- 第2部分 [英] Can shapeless Record type be used as a Poly1? - Part 2
问题描述
因为我没有从第 1 部分得到答案:
Since I didn't get an answer from the Part 1:
shapeless Record 类型可以用作 Poly1 吗?
我认为无形中不存在此功能.所以我决定自己的命运,自己写一篇:
I assume this feature doesn't exist in shapeless. So I decided own my fate and to write one myself:
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 次调用,我认为这是一种不安全的黑客攻击,可以规避类型检查器在单例类型上的陷阱.应该做些什么来改进它?
It works as anticipated, the only problems are 2 invocation of asInstanceOf
which I consider to be an unsafe hack to circumvent typechecker's pitfall on singleton types. What should be done to improve it?
如果你想知道它的能力,这是我的测试代码:
In case you want to know its capability, this is my test code:
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")
}
UPDATE 1:这只是我观察到的所有问题之一,如果我将测试用例更改为等效的内容:
UPDATE 1: this is just one of all the problems I have observed, if I change the test case into something equivalent:
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
两个测试用例有什么区别?val/object 是否都获得了不稳定的路径,因此它们的依赖类型具有局部作用域?
What's the difference between 2 test cases? Are val/object get both unstable paths so their dependent types have local scope?
推荐答案
请参阅我对第 1 部分的回答.
Please see my answer for Part 1.
关于第 2 部分,您可以更轻松地定义 implicit def getter
而无需 asInstanceOf
使用您已经拥有的类型类作为隐式参数(而不是扩展方法和 见证
)
Regarding Part 2, you can define implicit def getter
without asInstanceOf
much easier using type class that you already have as an implicit parameter (instead of extension method and 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
来定义.否则你必须导入隐式
Regarding update, it's common situation in Shapeless that polymorphic functions should be defined via objects rather than val
s. Otherwise you have to import implicits
val get = GetV(record)
import get._
这篇关于shapeless Record 类型可以用作 Poly1 吗?- 第2部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!