我有一种情况,我想在arity上抽象,并在一个或多个" raw"之间建立类型协议。类型(下面有A
和B
),一个应返回相应Seq(Option[A], Option[B], ...)
个类型(下面名为extract
)的方法,以及一组字段配置(名为{下面的{1}},每个都知道如何获得相应的" raw"类型。
在下面的代码中,理想情况下,我希望configs
和Dimensions1
不存在。如果我必须做某种Dimension2
- 就像递归的头/尾构造一样,我会对此感到满意。 :)
s.c.i.List
答案 0 :(得分:1)
如果我很好地理解了这个问题,你会想要一个给出HList
的函数
DimensionConfig[T]
会为您提供Dimension
类型参数All
和Configs
设置为正确的类型和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
不再需要 Dimensions1
和Dimensions2
了!并且您可以同时获得Dimensions
任意arities,例如:
val dimensions4 = dimensions(intConfig :: stringConfig :: intConfig :: stringConfig :: HNil)
val res4 = dimensions4.extractAll(JsonEventRecord()) // Option[Int] :: Option[String] :: Option[Int] :: Option[String] :: HNil