【问题标题】:How to provide evidence to case class constructor in proper way which depends on argument type class如何以适当的方式为案例类构造函数提供证据,这取决于参数类型类
【发布时间】:2019-06-10 09:47:00
【问题描述】:

我是连词类型

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)

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

【问题讨论】:

    标签: scala types implicit union-types


    【解决方案1】:

    尝试参数化案例类:

      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 方法是处理构造函数中这种依赖关系的标准解决方法(123)。另一种方法是在 Dotty 中等待真正的联合类型(当前的方法只是部分模拟它们)或在 Scala 中解析 SI-5712

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

    【讨论】:

    • 事情是:我正在尝试为层次结构中的每个类转义伴随对象,使 C 类类型参数化需要证据定义中的类型参数(A |∨| B |∨| C[T]) - 但我不想知道 C 中的什么类型类,直到我调用它。
    猜你喜欢
    • 2015-05-16
    • 2011-06-04
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 1970-01-01
    • 2017-03-25
    • 2017-09-14
    • 1970-01-01
    相关资源
    最近更新 更多