Как определить признаки, которые статически гарантируют, что объект и одно из его полей имеют одинаковую метку - PullRequest
1 голос
/ 02 ноября 2019

Вопрос:

Рассмотрим простой ADT T = A | B, то есть

sealed trait T
case object A extends T
case object B extends T

и классы Inner и Outer с меткой в ​​T, такой, что Outer содержит Inner.

trait Inner {
  val label: T
}

trait Outer {
  val label: T
  val i: Inner
}

Я бы хотел статически обеспечить, чтобы оба Inner внутри Outer имели одинаковую метку. Каков был бы идиоматический подход для введения такой гарантии в Scala?


Моя попытка:

Путем включения типов в качестве полей и соответствующих уточнений.

trait Inner {
  type Label <: T
  val label: Label
}

trait Outer { self =>
  type Label <: T
  val label: Label
  val i: Inner {type Label = self.Label}
}

Это работает до такой степени, в которой дано Inner объектов с A и B,

object IA extends Inner {
  override type Label = A.type
  override val label: A.type = A
}

object IB extends Inner {
  override type Label = B.type
  override val label: B.type = B
}

и Outer с Aможно взять только IA, но не IB.

object OA extends Outer {
  override type Label = A.type
  override val label: A.type = A
  override val i: Inner{type Label = A.type} = IA
}

Хотя есть как минимум два недостатка.

1) Эта логика не обеспечивается чертами Inner и Outer. Объект должен иметь конкретное значение метки A или B, но его тип вместо A.type или B.type может быть шире T.

object I2A extends Inner {
  override type Label = T
  override val label: T = A
}

object O2B extends Outer {
  override type Label = T
  override val label: T = B
  override val i: Inner{type Label = T} = I2A
}

2), поскольку метки должныбыть одноэлементными объектами было бы неплохо, если бы можно было вызвать значение из типа. то есть что-то вроде:

trait Inner {
  type Label <: T
  val label: ??? // summon the single value for the singleton of type Label
}

trait Outer { self =>
  type Label <: T
  val label: ??? // summon the single value for the singleton of type Label
  val i: Inner {type Label = self.Label}
}

, но первый недостаток уже показывает, что это невозможно, поскольку Label может быть шире, чем A.type и B.type.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...