【问题标题】:Passing a Shapeless Extensible Record to a Function将无形可扩展记录传递给函数
【发布时间】:2015-08-10 06:21:46
【问题描述】:

我正在尝试学习 Shapeless(使用版本 2.10.2)。我创建了一个非常简单的可扩展记录:

val rec1 = ("foo" ->> 42) :: HNil

根据 REPL,this 有类型

shapeless.::[Int with shapeless.record.KeyTag[String("foo"),Int],shapeless.HNil]

我正在尝试定义一个简单的函数:

def fun(x: ::[Int with KeyTag[String("foo"), Int], HNil]) = x("foo")

但它甚至无法编译。我不能在类型声明中使用 String("foo") 并得到错误。

我有两个问题:

  1. 如何在我的代码中指定可扩展记录的类型?
  2. 处理具有更多字段的记录时,类型声明的长度和复杂性将难以管理。给定记录的特定实例或其他解决方法,有没有办法为该类型创建别名?

编辑

我发现:

val rec1 = ("foo" ->> 42) :: HNil
val rec2 = ("foo" ->> 43) :: HNil
var x = rec1
x = rec2

效果很好。我得出结论rec1、rec2 和x 属于同一类型。我只是不知道如何在代码中表达这种类型!

【问题讨论】:

    标签: scala shapeless


    【解决方案1】:

    这里有一些更笼统的东西,我认为可能会回答你的问题。假设我们要编写一个方法,该方法可以处理带有"foo" 键的任何记录。我们可以结合使用见证人和选择器:

    import shapeless._, record._, syntax.singleton._
    
    val w = Witness("foo")
    
    def fun[L <: HList](xs: L)(implicit sel: ops.record.Selector[L, w.T]) = xs("foo")
    

    然后:

    scala> fun(("foo" ->> 42) :: HNil)
    res0: Int = 42
    

    或者:

    scala> fun(("bar" ->> 'a) :: ("foo" ->> 42) :: HNil)
    res1: Int = 42
    

    如果我们真的想只允许没有其他字段的记录,我们可以这样写:

    def fun(l: Int with KeyTag[w.T, Int] :: HNil) = l("foo")
    

    但这与通常使用记录的方式有些不一致。

    我们必须精确地定义见证,因为 Scala 2.10 没有提供任何直接引用单例类型的方法 - 例如,请参阅 Alois Cochard 的 Shona 项目的 my fork 进行一些讨论。

    作为最后的免责声明,我自己现在才刚刚熟悉 Shapeless 2.0,但我认为即使是 Miles 也没有足够的魔力来绕过这个限制。

    【讨论】:

    • 为了记录,迈尔斯刚刚说on Twitter他也许能够“在 2.0.0 最终版之前消除一些语法混乱”。
    • 如果我们有很多类似 fun 的函数,我们必须为每个函数重复隐式参数。如果这些函数必须访问多个字段(例如:foo、bar、...),那将是痛苦且容易出错的。有没有办法分解选择器的声明?
    【解决方案2】:

    从 shapeless 2.1.0 开始,有一个 new syntax 来表示记录类型:

    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    import shapeless._
    import shapeless.record._
    import shapeless.syntax.singleton._
    
    def fun(x: Record.`"foo" -> Int`.T) = x("foo")
    
    // Exiting paste mode, now interpreting.
    
    import shapeless._
    import shapeless.record._
    import shapeless.syntax.singleton._
    fun: (x: shapeless.::[Int with shapeless.labelled.KeyTag[String("foo"),Int],shapeless.HNil])Int
    
    scala> fun( ("foo" ->> 42) :: HNil )
    res2: Int = 42
    
    scala> fun( ("foo" ->> 42) :: ("bar" ->> 43) :: HNil )
    <console>:30: error: type mismatch;
     found   : shapeless.::[Int with shapeless.labelled.KeyTag[String("foo"),Int],shapeless.::[Int with shapeless.labelled.KeyTag[String("bar"),Int],shapeless.HNil]]
     required: shapeless.::[Int with shapeless.labelled.KeyTag[String("foo"),Int],shapeless.HNil]
           fun( ("foo" ->> 42) :: ("bar" ->> 43) :: HNil )
    

    但是选择器可能是 OP 用例的最佳方法。

    【讨论】:

      猜你喜欢
      • 2013-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-25
      • 2014-08-31
      相关资源
      最近更新 更多