在函数中包装无形FieldType创建

时间:2017-08-01 01:02:24

标签: scala shapeless

有没有办法创建一个隐式类来提供自定义函数来返回与记录样式单例运算符<div id="count">count</div> <div id="selection">click selection</div>具有相同类型的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") 中的宏所挫败。任何建议都会有所帮助!

更新

这样做的动机源于创建DSL并尝试仔细控制其语法。上面的简化示例跳过了隐式类在DSL中实现的目的 - 特别是将函数应用于T,返回DSL中其他地方所需的类型类。

更典型的案例是:

mkSingletonOps

以便以下两个值具有相同的类型:

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") 的表达式是DSL的理想语法。

1 个答案:

答案 0 :(得分:1)

可能没有。

  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中的s.type是什么?在隐式转换之前它是'test但在此之后它只是FieldMaker[S]实例的一个字段(实例,它仅在隐式转换期间存在)所以我们有存在类型。只要我们有存在类型,我们就不能回到'test

这就是影响工作的方式。

实际上我最终找到了使second的方式与first 相同的方式(尽管它使用.narrow。我用类型类和隐式转换替换了隐式转换。

  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")