如何根据参数类型类以适当方式向案例类构造函数提供证据

时间:2019-01-16 10:16:24

标签: scala types implicit union-types

我有Conjuction类型

type ![S] = S => Nothing
type !![S] = ![![S]]
type ∨[T, U] = ![![T] with ![U]]
type |∨|[T, U] = {type λ[X] = !![X] <:< (T ∨ U)}

类层次结构:a,b,c,d,n

abstract class State
case class A() extends State
case class B() extends State
case class N() extends State

// what should i place in ??? , state.type doesn't compile : 
// Error: not found value state ... in evidence
case class C(state: State)(implicit ev: (A |∨| B)#λ[???]) 
case class D(state: State)(implicit ev: (A |∨| B |∨| C)#λ[???])

样本:

val a = A(); val b = B(); val n = N()
val ca = C(a); val cb = C(b)
//this shouldn't compile because evidence (A |∨| B)
val cn = C(n)

如何以正确的方式实施证据?

1 个答案:

答案 0 :(得分:0)

尝试对案例类进行参数化

  type ![S] = S => Nothing
  type !![S] = ![![S]]
  type ∨[T, U] = ![![T] with ![U]]
  type |∨|[T, U] = {type λ[X] = !![X] <:< (T ∨ U)}

  abstract class State
  case class A() extends State
  case class B() extends State
  case class N() extends State

  case class C[S <: State](state: S)(implicit ev: (A |∨| B)#λ[S])

  val a = A()
  val b = B()
  val n = N()

  val ca = C(a)
  val cb = C(b)
  // val cn = C(n) // doesn't compile

编码更多类

  type ![S] = S => Nothing
  type !![S] = ![![S]]

  trait Disj[T] {
    type or[S] = Disj[T with ![S]]
    type apply = ![T]
  }

  // for convenience
  type disj[T] = { type or[S] = Disj[![T]]#or[S] }

  type w[T, U, V] = disj[T]#or[U]#or[V]#apply
  type ww[T, U, V] = {type λ[X] = !![X] <:< w[T, U, V]}

  abstract class State
  case class A() extends State
  case class B() extends State
  case class C() extends State
  case class N() extends State

  case class D[S <: State](state: S)(implicit ev: ww[A, B, C]#λ[S])

  val a = A()
  val b = B()
  val c = C()
  val n = N()

  val da = D(a)
  val db = D(b)
  val dc = D(c)
//  val dn = D(n) // doesn't compile

或者您可以使用apply方法

  type ![S] = S => Nothing
  type !![S] = ![![S]]
  type ∨[T, U] = ![![T] with ![U]]
  type |∨|[T, U] = {type λ[X] = !![X] <:< (T ∨ U)}

  abstract class State
  case class A() extends State
  case class B() extends State
  case class N() extends State

  class C private(state: State)
  object C {
    def apply(state: State)(implicit ev: (A |∨| B)#λ[state.type]) = new C(state)
  }

  val a = A()
  val b = B()
  val n = N()

  val ca = C(a)
  val cb = C(b)
//  val cn = C(n) // doesn't compile

如果您想使用apply方法避免伴随对象(出于某种原因),可以考虑使用辅助构造函数

  type ![S] = S => Nothing
  type !![S] = ![![S]]
  type ∨[T, U] = ![![T] with ![U]]
  type |∨|[T, U] = {type λ[X] = !![X] <:< (T ∨ U)}

  abstract class State
  case class A() extends State
  case class B() extends State
  case class N() extends State

  // "ignored" is to avoid constructor ambiguity
  class C private(state: State, ignored: Int) {
    def this(state: State)(implicit ev: (A |∨| B)#λ[state.type]) = this(state, 0)
  }

  val a = A()
  val b = B()
  val n = N()

  val ca = new C(a)
  val cb = new C(b)
//  val cn = new C(n) // doesn't compile

使用辅助构造函数或伴随对象的apply方法是处理构造函数(1 2 3中这种依赖关系的一种标准解决方法。另一种选择是等待Dotty中的实际联合类型(当前方法只是对它们的部分仿真)或在Scala中解析SI-5712

要自动生成伴随对象,可以考虑使用宏或代码生成。