将无形可扩展记录传递给函数

时间:2013-10-10 23:56:00

标签: scala shapeless

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

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

根据REPL,这有类型

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. 使用包含更多字段的记录时,类型声明的长度和复杂性将无法管理。在给定记录的特定实例或其他一些变通方法的情况下,有没有办法为类型创建别名?
  3. 修改

    我发现:

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

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

2 个答案:

答案 0 :(得分:26)

我觉得这可能会回答你的问题。假设我们想要编写一个可以使用"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的my fork项目的Shona进行讨论。

我将添加作为最终免责声明,我现在才刚刚熟悉Shapeless 2.0,但我认为即使是Miles也不足以克服这个限制。

答案 1 :(得分:6)

从无形的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用例的最佳方法。