scala - 可扩展的记录类型
问题描述
我正在尝试使用无形的可扩展记录进行简单的练习。
这是一个名为 的类型类Projection
,它应该能够在某种程度上结合 和 的Updater
功能Remover
:
import shapeless._
import shapeless.tag._
import shapeless.record._
import shapeless.labelled._
import shapeless.ops.record._
import shapeless.syntax._
// Probably way too many imports
trait Projection[A <: HList, K, V] {
type B <: HList
def to(a: A, v: V): B
def from(b: B): A
}
object Projection {
type Aux[A <: HList, K, V, B0 <: HList] = Projection[A, K, V] { type B = B0 }
type Key[K] = Symbol with Tagged[K]
type F[K, V] = V with FieldType[Key[K], V]
implicit def mkProjection[A <: HList, K, V, B0 <: HList](implicit
keyWitness: Witness.Aux[K],
updater: Updater.Aux[A, F[K, V], B0],
remover: Remover.Aux[B0, K, (V, A)]
): Projection.Aux[A, K, V, B0] = new Projection[A, K, V] {
type B = B0
def from(b: B0): A = b - keyWitness
def to(a: A, v: V): B0 = a + field[Key[K]](v)
}
}
我相当简单的测试
import Projection._
val thirdFieldWitness = Witness("thirdField")
val projector = implicitly[Projection[HNil, thirdFieldWitness.T, Boolean]]
不幸的是由于错误而失败
could not find implicit value for parameter e: Projection[shapeless.HNil,ProjectionSpec.this.thirdFieldWitness.T,Boolean]
[error] val projector = implicitly[Projection[HNil, thirdFieldWitness.T, Boolean]]
-Xlog-implicits
显示它的原因:
ProjectionSpec.scala:18:35: record.this.Remover.mkRemover is not a valid implicit value for shapeless.ops.record.Remover.Aux[Boolean with shapeless.labelled.FieldType[Projection.Key[ProjectionSpec.this.thirdFieldWitness.T],Boolean] :: shapeless.HNil,ProjectionSpec.this.thirdFieldWitness.T,(Boolean, shapeless.HNil)] because:
[info] hasMatchingSymbol reported error: No field String("thirdField") in record type Boolean with shapeless.labelled.FieldType[Projection.Key[ProjectionSpec.this.thirdFieldWitness.T],Boolean] :: shapeless.HNil
[info] val projector = implicitly[Projection[HNil, thirdFieldWitness.T, Boolean]]
请帮助我理解此消息并告诉我如何修复它。
是否有一种更简单的方法来对标记的泛型进行这种扩展和缩短?
解决方案
除了-Xlog-implicits
,调试隐式的另一种标准方法是手动解决它们并查看编译错误。
尝试
object Projection {
type Aux[A <: HList, K, V, B0 <: HList] = Projection[A, K, V] { type B = B0 }
type Key[K] = Symbol with Tagged[K]
type F[K, V] = FieldType[Key[K], V]
implicit def mkProjection[A <: HList, K, V, B0 <: HList](implicit
keyWitness: Witness.Aux[Key[K]],
updater: Updater.Aux[A, F[K, V], B0],
remover: Remover.Aux[B0, Key[K], (V, A)]
): Projection.Aux[A, K, V, B0] = new Projection[A, K, V] {
type B = B0
def from(b: B0): A = b - keyWitness
def to(a: A, v: V): B0 = a + field[Key[K]](v)
}
}
然后
implicitly[Projection.Aux[HNil, "thirdField", Boolean, Record.`'thirdField -> Boolean`.T]]
编译。
但是虽然implicitly[thirdFieldWitness.T =:= "thirdField"]
implicitly[Projection.Aux[HNil, thirdFieldWitness.T, Boolean, Record.`'thirdField -> Boolean`.T]]
仍然没有编译。但是手动解决
implicitly[Projection.Aux[HNil,
thirdFieldWitness.T,
Boolean,
Record.`'thirdField -> Boolean`.T
]](Projection.mkProjection(
implicitly[Witness.Aux[Witness.`'thirdField`.T]],
implicitly[Updater.Aux[HNil, FieldType[Witness.`'thirdField`.T, Boolean], Record.`'thirdField -> Boolean`.T]],
implicitly[Remover.Aux[Record.`'thirdField -> Boolean`.T, Witness.`'thirdField`.T, (Boolean, HNil)]]
))
编译。事情似乎是implicitly[Witness.Aux[Key["thirdField"]]]
编译但implicitly[Witness.Aux[Key[thirdFieldWitness.T]]]
不编译(“Symbol with Tagged[thirdFieldWitness.T]
不是单例类型”)。
如果添加,则可以修复编译
implicit def extraWitness[S <: String](implicit
w: Witness.Aux[S]
): Witness.Aux[Symbol @@ S] = Witness.mkWitness(tag[S](Symbol(w.value)))
我会使用标准的基于符号的 API
object Projection {
type Aux[A <: HList, K, V, B0 <: HList] = Projection[A, K, V] { type B = B0 }
type F[K, V] = FieldType[K, V]
implicit def mkProjection[A <: HList, K, V, B0 <: HList](implicit
keyWitness: Witness.Aux[K],
updater: Updater.Aux[A, F[K, V], B0],
remover: Remover.Aux[B0, K, (V, A)]
): Projection.Aux[A, K, V, B0] = new Projection[A, K, V] {
type B = B0
def from(b: B0): A = b - keyWitness
def to(a: A, v: V): B0 = a + field[K](v)
}
}
implicitly[Projection.Aux[HNil, Witness.`'thirdField`.T, Boolean, Record.`'thirdField -> Boolean`.T]]
val thirdFieldWitness = Witness('thirdField)
implicitly[Projection.Aux[HNil, thirdFieldWitness.T, Boolean, Record.`'thirdField -> Boolean`.T]]
推荐阅读
- javascript - 尝试将我的 javascript 代码导入一个 js 文件并从中创建一个 html 页面
- ios - 在滚动时更改后退按钮的色调颜色
- python - 将绘图转换为 1 和 0 的数组
- typescript - 如何在打字稿中从反应表中提供 Cell 可选类型
- pandas - 如何通过比较两列的值来删除重复项?
- typescript - Vue.js - 父级基于无渲染子数据生成组件
- c# - 创建重复的子数组并随机化顺序c#
- ios - 如何让键盘在应用程序启动时显示?
- sql - SQL Hadoop - 组合两个表并求和
- reactjs - How do I get the decimal in the right place with mongoose-currency?