Combinatorial data structures via finite existential types

Simpler alternative to previous wiring diagram schema:

type HasPorts {
  ftype In
  ftype Out
}

type DWD {
  ftype Box <: HasPorts
  ftype Wire

  type OutPort {
    val box: Box
    val port: box.Out
  }
  
  type InPort {
    val box: Box
    val port: box.In
  }
  
  def src(w: Wire): OutPort
  def tgt(w: Wire): InPort
}

Variation with outer ports:

type HasPorts {
  ftype In
  ftype Out
}

type DWD <: HasPorts {
  ftype Box <: HasPorts
  ftype Wire

  enum SrcPort {
    case Inner(box: Box, port: box.Out)
    case Outer(port: In)
  }
  
  enum TgtPort {
     case Inner(box: Box, port: box.In)
     case Outer(port: Out)
  }
  
  def src(w: Wire): SrcPort
  def tgt(w: Wire): TgtPort
}

Putting things in the boxes via refinement types.

type FilledDWD[T <: HasPorts] <: HasPorts {
  val dwd: DWD
  type In = dwd.In
  type Out = dwd.Out
  
  def content(b: dwd.Box): T { ftype In = b.In, ftype Out = b.Out }
}

enum NestedDWD[T <: HasPorts] <: HasPorts {
  case Primitive(value: T) {
    ftype In = value.In
    ftype Out = value.Out
  }
  case Nested(filled: FilledDWD[NestedDWD[T]]) {
    ftype In = filled.In
    ftype Out = filled.Out
  }
}