微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

shapeless Record 类型可以用作 Poly1 吗? - 第2部分

如何解决shapeless Record 类型可以用作 Poly1 吗? - 第2部分

因为我没有从第 1 部分得到答案:

Can shapeless Record type be used as a Poly1?

我认为无形中不存在此功能。所以我决定自己的命运,自己写一篇:

  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 次调用,我认为这是绕过类型检查器在单例类型上的陷阱的不安全黑客。应该做些什么来改进它?

如果你想知道它的能力,这是我的测试代码

  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:这只是我观察到的所有问题之一,如果我将测试用例更改为等效的内容

  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 是否都获得了不稳定的路径,因此它们的依赖类型具有局部作用域?

解决方法

请参阅我对第 1 部分的回答。

关于第 2 部分,您可以使用已经作为隐式参数(而不是扩展方法和 implicit def getter)的类型类更轻松地定义 asInstanceOf 而不使用 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 来定义。否则你必须导入隐式

val get = GetV(record)
import get._

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。