管道依赖的类型级定义

Type level definition of pipeline dependency

我想构建一个管道依赖关系,其中 2nd 级别取决于 1st 一个,3rd 取决于 2nd AND 1st 等等…

我已经定义了这样的结构

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 

到目前为止一切正常。但我无法让它与依赖于前两个结构的第三个结构一起工作。我试过 shapeless ProductCoproduct 但我无法让它正常工作。我知道它必须是一个 Product 意思和类型,它意味着使用无形 HList。请帮助:)

您可以将 Shapeless' heterogenous lists (HList) 与更多自定义的自制 HList 一起使用。我会选择前者,因为它会更清晰、更容易理解。下面代码中的主要思想是,您将关卡的类型链与所有元素类型的 "accumulated" 类型保持在一起。

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