用无形的方式摆脱灵魂的篝火?

时间:2014-11-18 01:05:06

标签: scala shapeless hlist

我有一种情况,我想在arity上抽象,并在一个或多个" raw"之间建立类型协议。类型(下面有AB),一个应返回相应Seq(Option[A], Option[B], ...)个类型(下面名为extract)的方法,以及一组字段配置(名为{下面的{1}},每个都知道如何获得相应的" raw"类型。

在下面的代码中,理想情况下,我希望configsDimensions1不存在。如果我必须做某种Dimension2 - 就像递归的头/尾构造一样,我会对此感到满意。 :)

s.c.i.List

1 个答案:

答案 0 :(得分:1)

如果我很好地理解了这个问题,你会想要一个给出HList的函数 DimensionConfig[T]会为您提供Dimension类型参数AllConfigs设置为正确的类型和extractAll的实现。 (纠正我,如果我错了: - )

因此,无形状的依赖函数应该能够提供:

trait DimensionsOf[L <: HList] extends DepFn1[L] {
  type All <: HList
  type Out = Dimensions.Aux[All, L]
}

def dimensions[L <: HList](configs: L) 
 (implicit dimensionsOf: DimensionsOf[L]): dimensionsOf.Out =
  dimensionsOf(configs)

上面定义了一个“伪”依赖函数,它接受HList作为参数(我们稍后会使它只接受由DimensionConfig[T]组成的HLists),并返回一个Dimensions它的类型参数集(参见下面的Dimensions.Aux的定义 - 我们将使All成为由Option[T]组成的与输入HList类型匹配的HList。)

然后,我们必须在某些值上提供此依赖函数的定义,此处由DimensionsConfig[T]组成的HLists - 这通常在依赖函数特征的单例对象中生成:

object DimensionsOf {
  type Aux[L <: HList, All0 <: HList] = DimensionsOf[L] { type All = All0 }

  implicit val dimensionsOfHNil: DimensionsOf.Aux[HNil, HNil] =
    new DimensionsOf[HNil] {
      type All = HNil
      def apply(l: HNil) = new Dimensions {
        type All = HNil
        type Configs = HNil
        val configs = HNil
        def extractAll(rec: JsonEventRecord) = HNil
      }
    }

    implicit def dimensionsOfHCons[H, CT <: HList]
     (implicit dimensionsOfTail: DimensionsOf[CT]): Aux[DimensionConfig[H] :: CT, Option[H] :: dimensionsOfTail.All] =
      new DimensionsOf[DimensionConfig[H] :: CT] {
        type All = Option[H] :: dimensionsOfTail.All
        def apply(l: DimensionConfig[H] :: CT) = new Dimensions {
          type All = Option[H] :: dimensionsOfTail.All
          type Configs = DimensionConfig[H] :: CT
          val configs = l
          val tailDimensions = dimensionsOfTail(l.tail)
          def extractAll(rec: JsonEventRecord) = l.head.extract(rec) :: tailDimensions.extractAll(rec)
        }
      }
  }

我们在DimensionsOf处定义HNil,在DimensionConfig[H] :: CT形式定义了HLists,其中CT是一个HList,DimensionsOf是自定义的(正如我们所要求的 - 然后使用 - 暗示证明这一点)。

上述定义中使用的

Dimensions.Aux定义为

object Dimensions {
  type Aux[All0 <: HList, Configs0 <: HList] = Dimensions { type All = All0; type Configs = Configs0 }
}

以上定义的dimensions函数可以这样使用:

val intConfig = DimensionConfig[Int]("Int", _ => Some(2))
val stringConfig = DimensionConfig[String]("String", _ => Some("a"))

val dimensions1 = dimensions(intConfig :: HNil)
val res1 = dimensions1.extractAll(JsonEventRecord()) // Option[Int] :: HNil

val dimensions2 = dimensions(intConfig :: stringConfig :: HNil)
val res2 = dimensions2.extractAll(JsonEventRecord()) // Option[Int] :: Option[String] :: HNil
不再需要

Dimensions1Dimensions2了!并且您可以同时获得Dimensions任意arities,例如:

val dimensions4 = dimensions(intConfig :: stringConfig :: intConfig :: stringConfig :: HNil)
val res4 = dimensions4.extractAll(JsonEventRecord()) // Option[Int] :: Option[String] :: Option[Int] :: Option[String] :: HNil