在函数中包装 Shapeless FieldType 创建
Wrapping Shapeless FieldType creation in a function
有没有办法创建隐式 class 来为 return 与记录样式单例运算符 ->>
具有相同类型的 FieldType 提供自定义函数?
我想做类似的事情:
import shapeless.syntax.singleton._
implicit class FieldMaker[S <: Symbol](val s: S) {
def make[T](t: T) = s ->> t
}
所以下面两个值有相同的类型:
val first = 'test ->> Foo("bar")
val second = 'test make Foo("bar")
在之前的尝试中,我一直被 mkSingletonOps
中的宏所挫败。任何建议都会有所帮助!
更新:
这样做的动机源于创建 DSL 并试图仔细控制其语法。上面的简化示例跳过了此隐式 class 在 DSL 中实现的目的——具体来说,将函数应用于 T returning 类型 class,这在 DSL 的其他地方是需要的。
一个更典型的案例是:
import shapeless.syntax.singleton._
def func(t: T): SomeTypeclass[T] = _ // elided
implicit class FieldMaker[S <: Symbol](val s: S) {
def make[T](t: T) = s ->> func(t)
}
所以下面两个值有相同的类型:
val first = 'test ->> func(Foo("bar"))
val second = 'test make Foo("bar")
分配给 second
的表达式是 DSL 所需的语法。
可能没有。
import shapeless.Witness
import shapeless.labelled.FieldType
import shapeless.syntax.singleton._
implicit class FieldMaker[S <: Symbol](val s: S) {
def make[T](t: T): FieldType[s.type, T] = s ->>[T] t
}
case class Foo(s: String)
val first: FieldType[Witness.`'test`.T, Foo] = 'test ->>[Foo] Foo("bar")
val second: FieldType[fm.s.type, Foo] forSome { val fm: FieldMaker[Symbol] } =
'test make[Foo] Foo("bar")
val third: FieldType[fm.s.type, Foo] forSome { val fm: FieldMaker[Witness.`'test`.T] } =
'test.narrow make[Foo] Foo("bar")
s ->>[T] t
的类型是 FieldType[s.type, T]
,这与类型参数 S
无关。
但是 s.type
中的 s
是什么?在隐式转换之前它是 'test
但之后它只是 FieldMaker[S]
实例的一个字段(实例,仅在隐式转换期间存在)所以我们有存在类型。一旦我们有了存在类型,我们就不能回到 'test
.
这就是隐式的工作原理。
实际上我终于找到了制作与first
相同类型的second
的方法(尽管它使用.narrow
)。我用类型 class 和隐式转换替换了隐式转换。
import shapeless.Witness
import shapeless.labelled.FieldType
import shapeless.syntax.singleton._
import shapeless.tag.@@
trait FieldMaker[S <: Symbol, T] {
def make(t: T): FieldType[S, T]
}
object FieldMaker {
implicit def mkFieldMaker[/*S <: Symbol*/U, T](implicit
witness: Witness.Aux[/*S*/Symbol @@ U]
): FieldMaker[/*S*/Symbol @@ U, T] = {
val name: /*S*/Symbol @@ U = witness.value
new FieldMaker[/*S*/Symbol @@ U, T] {
override def make(t: T): FieldType[/*S*/Symbol @@ U, T] =
(name ->>[T] t).asInstanceOf[FieldType[/*S*/Symbol @@ U, T]]
}
}
object op {
implicit class FieldMakerOp[S <: Symbol](s: S) {
def make[T](t: T)(implicit fm: FieldMaker[S, T]): FieldType[S, T] = fm.make(t)
}
}
}
case class Foo(s: String)
val first: FieldType[Witness.`'test`.T, Foo] = 'test ->>[Foo] Foo("bar")
import FieldMaker.op._
val second: FieldType[Witness.`'test`.T, Foo] = 'test.narrow make/*[Foo]*/ Foo("bar")
有没有办法创建隐式 class 来为 return 与记录样式单例运算符 ->>
具有相同类型的 FieldType 提供自定义函数?
我想做类似的事情:
import shapeless.syntax.singleton._
implicit class FieldMaker[S <: Symbol](val s: S) {
def make[T](t: T) = s ->> t
}
所以下面两个值有相同的类型:
val first = 'test ->> Foo("bar")
val second = 'test make Foo("bar")
在之前的尝试中,我一直被 mkSingletonOps
中的宏所挫败。任何建议都会有所帮助!
更新:
这样做的动机源于创建 DSL 并试图仔细控制其语法。上面的简化示例跳过了此隐式 class 在 DSL 中实现的目的——具体来说,将函数应用于 T returning 类型 class,这在 DSL 的其他地方是需要的。
一个更典型的案例是:
import shapeless.syntax.singleton._
def func(t: T): SomeTypeclass[T] = _ // elided
implicit class FieldMaker[S <: Symbol](val s: S) {
def make[T](t: T) = s ->> func(t)
}
所以下面两个值有相同的类型:
val first = 'test ->> func(Foo("bar"))
val second = 'test make Foo("bar")
分配给 second
的表达式是 DSL 所需的语法。
可能没有。
import shapeless.Witness
import shapeless.labelled.FieldType
import shapeless.syntax.singleton._
implicit class FieldMaker[S <: Symbol](val s: S) {
def make[T](t: T): FieldType[s.type, T] = s ->>[T] t
}
case class Foo(s: String)
val first: FieldType[Witness.`'test`.T, Foo] = 'test ->>[Foo] Foo("bar")
val second: FieldType[fm.s.type, Foo] forSome { val fm: FieldMaker[Symbol] } =
'test make[Foo] Foo("bar")
val third: FieldType[fm.s.type, Foo] forSome { val fm: FieldMaker[Witness.`'test`.T] } =
'test.narrow make[Foo] Foo("bar")
s ->>[T] t
的类型是 FieldType[s.type, T]
,这与类型参数 S
无关。
但是 s.type
中的 s
是什么?在隐式转换之前它是 'test
但之后它只是 FieldMaker[S]
实例的一个字段(实例,仅在隐式转换期间存在)所以我们有存在类型。一旦我们有了存在类型,我们就不能回到 'test
.
这就是隐式的工作原理。
实际上我终于找到了制作与first
相同类型的second
的方法(尽管它使用.narrow
)。我用类型 class 和隐式转换替换了隐式转换。
import shapeless.Witness
import shapeless.labelled.FieldType
import shapeless.syntax.singleton._
import shapeless.tag.@@
trait FieldMaker[S <: Symbol, T] {
def make(t: T): FieldType[S, T]
}
object FieldMaker {
implicit def mkFieldMaker[/*S <: Symbol*/U, T](implicit
witness: Witness.Aux[/*S*/Symbol @@ U]
): FieldMaker[/*S*/Symbol @@ U, T] = {
val name: /*S*/Symbol @@ U = witness.value
new FieldMaker[/*S*/Symbol @@ U, T] {
override def make(t: T): FieldType[/*S*/Symbol @@ U, T] =
(name ->>[T] t).asInstanceOf[FieldType[/*S*/Symbol @@ U, T]]
}
}
object op {
implicit class FieldMakerOp[S <: Symbol](s: S) {
def make[T](t: T)(implicit fm: FieldMaker[S, T]): FieldType[S, T] = fm.make(t)
}
}
}
case class Foo(s: String)
val first: FieldType[Witness.`'test`.T, Foo] = 'test ->>[Foo] Foo("bar")
import FieldMaker.op._
val second: FieldType[Witness.`'test`.T, Foo] = 'test.narrow make/*[Foo]*/ Foo("bar")