管道依赖性的类型级别定义

时间:2015-08-13 16:45:07

标签: scala shapeless type-level-computation

我想构建一个管道依赖项,其中 2nd 级别依赖于 1st 一个, 3rd 依赖于 2nd AND 1st 等等......

我已经定义了这样的结构

      <scheme-name>example-distributed</scheme-name>

      <service-name>DistributedCache</service-name>

  <backing-map-scheme>
    <local-scheme>
      <scheme-ref>example-binary-backing-map</scheme-ref>
    </local-scheme>
  </backing-map-scheme>

  <autostart>true</autostart>
</distributed-scheme>

<local-scheme>
  <scheme-name>example-binary-backing-map</scheme-name>

  <eviction-policy>HYBRID</eviction-policy>
  <high-units>{back-size-limit 0}</high-units>
  <unit-calculator>BINARY</unit-calculator>
  <expiry-delay>0</expiry-delay>

  <cachestore-scheme></cachestore-scheme>
</local-scheme>

到目前为止一切正常。但我无法使用依赖于前两个结构的第三个结构。我尝试过无形trait Level[A <: Level[A]] { type DependsOn <: Level[DependsOn] val previousDependencies: List[DependsOn] } trait First extends Level[First] { type DependsOn = Nothing } trait Second extends Level[Second] { type DependsOn = First } class FirstLevel extends First { val previousDependencies = List.empty } class SecondLevel(val previousDependencies: List[FirstLevel]) extends Second Product,但我无法正常使用它。我知道它必须是Coproduct含义和类型,它意味着使用无形Product。请帮助:)

1 个答案:

答案 0 :(得分:1)

您可以使用Shapeless&#39; heterogenous lists(HLists)以及更多自定义的自定义HLists。我会和前者一起去,因为它会更清晰,更容易理解。下面的代码中的主要想法是你保持你的级别的类型链与&#34;累积&#34;途中所有元素类型的类型。

import shapeless.{HNil, HList}

sealed trait Level[MyElement] {
  type Previous <: Level[_]
  type MyList <: HList
  def elements: MyList
}
trait LNil extends Level[Nothing] {
  type MyElement = Nothing
  type MyList = HNil
}
trait LCons[MyElement] <: Level[MyElement] {
  type MyList = shapeless.::[List[MyElement], Previous#MyList]
}

如您所见,MyList从下面的级别保存所有元素类型的HList。现在我们可以提供不那么抽象的实现,允许轻松构建这样的级别:

object ConcreteLNil extends LNil {
  def elements = HNil
}

class ConcreteLCons[MyElement, PreviousList <: Level[_]]
  (thisElems: List[MyElement], val previous: PreviousList) 
    extends LCons[MyElement] {
  type Previous = PreviousList
  type MyElement = String
  def elements = thisElems :: previous.elements
}

您现在可以像这样使用它:

val first = new ConcreteLCons(1 :: 2 :: Nil, ConcreteLNil)
val second = new ConcreteLCons("x" :: "y" :: Nil, first)
val third = new ConcreteLCons(1.0 :: Nil, second)

third.elements
// List(1.0) :: List(x, y) :: List(1, 2) :: HNil