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

Edu*_*rdo 18 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")
Run Code Online (Sandbox Code Playgroud)

但它甚至没有编译.我不能在类型声明中使用String("foo"),并得到错误.

我有两个问题:

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

编辑

我发现:

val rec1 = ("foo" ->> 42) :: HNil
val rec2 = ("foo" ->> 43) :: HNil
var x = rec1
x = rec2
Run Code Online (Sandbox Code Playgroud)

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

Tra*_*own 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")
Run Code Online (Sandbox Code Playgroud)

然后:

scala> fun(("foo" ->> 42) :: HNil)
res0: Int = 42
Run Code Online (Sandbox Code Playgroud)

要么:

scala> fun(("bar" ->> 'a) :: ("foo" ->> 42) :: HNil)
res1: Int = 42
Run Code Online (Sandbox Code Playgroud)

如果我们真的只想允许没有其他字段的记录,我们可以编写以下内容:

def fun(l: Int with KeyTag[w.T, Int] :: HNil) = l("foo")
Run Code Online (Sandbox Code Playgroud)

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

我们必须准确定义见证,因为Scala 2.10没有提供任何直接引用单例类型的方法 - 例如参见的Alois Cochard的Shona项目的分支进行讨论.

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


Tai*_*aig 6

从无形2.1.0开始,有一种表达记录类型的新语法:

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 )
Run Code Online (Sandbox Code Playgroud)

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