0

我正在解决一个问题,我发现类型投影和抽象类型有一个新的奇怪问题。假设我有一个产生交易的系统,并且有一个我想桥接的对等系统。以下对我来说看起来不错:

trait Txn[S <: Sys[S]] {
  def peer: S#Peer#Tx
  def newID(): S#ID
  def newVar[A](id: S#ID, init: A): S#Var[A]
}
trait Sys[S <: Sys[S]] {
  type Tx <: Txn[S]
  type Peer <: Sys[Peer] // parallel system
  type Var[A]
  type ID
}

我可以使用直接系统:

def directWorks[S <: Sys[S]](implicit tx: S#Tx): Unit = {
  val id = tx.newID()
  val v  = tx.newVar(id, 0)
}

但不知何故,peer交易的方法存在缺陷,如下所示:

def indirectDoesnt[S <: Sys[S]](implicit tx: S#Tx): Unit = {
  val p   = tx.peer
  val id  = p.newID()
  val v   = p.newVar(id, 0) // what the **** - id is not compatible??
}

error: type mismatch;
 found   : id.type (with underlying type S#Peer#ID)
 required: _30129.Peer#ID where val _30129: S
          val v   = p.newVar(id, 0)
                             ^

我想变得聪明并解决它:

def clever[S <: Sys[S]](implicit tx: S#Tx): Unit = {
  def directWorks[S <: Sys[S]](implicit tx: S#Tx): Unit = {
    val id = tx.newID()
    val v  = tx.newVar(id, 0)
  }
  directWorks(tx.peer)
}

...但这也失败了,提供了更多关于问题所在的线索:

error: inferred type arguments [S#Peer] do not conform to method
       directWorks's type parameter bounds [S <: Sys[S]]
          directWorks(tx.peer)
          ^

这一切都表明,要么def peer: S#Peer#Tx引入一个问题,要么(更有可能?)type Peer <: Sys[Peer]当不用作类型参数但类型成员时有问题。

4

1 回答 1

0

现在这是一个几乎可以接受的解决方案。它基于“修复”中的表示类型的想法Sys;在一个具体的系统中S,我们总会有S#S#Tx == S#Tx等。我对这个解决方案的理解是,它将差异的责任从使用现场转移到了系统本身。

由于这涉及一些仪式,我仍然非常感谢有关删除或减少此仪式的其他答案;以及关于为什么这样做和省略调用fix不起作用的解释。

trait VarLike[ -Tx, A ] { def update( value: A )( implicit tx: Tx ) : Unit }

trait Sys[ S <: Sys[ S ]] {
   type Tx       <: Txn[ S ]
   type Var[ A ] <: VarLike[ S#Tx, A ]
   type ID
   type Peer     <: Sys[ Peer ]

   // 'pop' the representation type ?!
   def fix[ A ]( v: S#Peer#Var[ A ]) : Peer#Var[ A ]
   def peer( tx: S#Tx ) : Peer#Tx
}

trait Txn[ S <: Sys[ S ]] {
   def newID() : S#ID
   def newVar[ A ]( id: S#ID, init: A ) : S#Var[ A ]
   def system: S
}

现在有两个示例系统。第一的:

class InMemTx( val system: InMem ) extends Txn[ InMem ] {
   def newID() {}
   def newVar[ A ]( id: InMem#ID, init: A ) : InMem#Var[ A ] =
      new VarLike[ InMemTx, A ] {
         def update( v: A )( implicit tx: InMemTx ) {}
      }
}
class InMem extends Sys[ InMem ] {
   type Tx       = InMemTx
   type Var[ A ] = VarLike[ Tx, A ]
   type ID       = Unit
   type Peer     = InMem  // reflect back to ourself

   def fix[ A ]( v: Var[ A ]) : Var[ A ] = v
   def peer( tx: Tx ) : Tx = tx
}

第二:

class DurableTx( val system: Durable, val peer: InMem#Tx ) extends Txn[ Durable ] {
   def newID() = 33
   def newVar[ A ]( id: Durable#ID, init: A ) : Durable#Var[ A ] =
      new VarLike[ DurableTx, A ] {
        def update( v: A )( implicit tx: DurableTx ) {}
      }
}
class Durable extends Sys[ Durable ] {
   type Tx       = DurableTx
   type Var[ A ] = VarLike[ Tx, A ]
   type ID       = Int
   type Peer     = InMem

   def fix[ A ]( v: InMem#Var[ A ]) : InMem#Var[ A ] = v
   def peer( tx: Tx ) : InMem#Tx = tx.peer
}

并在使用现场验证:

// let's make sure we can use the system as intended
trait TestTrait[ S <: Sys[ S ]] {
   def v : S#Peer#Var[ Int ]

   def test( implicit tx: S#Tx ) {
      val s          = tx.system
      implicit val p = s.peer( tx )
      val vf         = s.fix( v ) // not cool...
      vf()            = 1
   }
}

// see if we can actually create variables
class TestImpl[ S <: Sys[ S ]]( implicit tx: S#Tx ) extends TestTrait[ S ] {
   val v = {
      val s          = tx.system
      implicit val p = s.peer( tx )
      val id         = p.newID()
      p.newVar( id, 0 )
   }
}
于 2012-09-25T22:17:32.457 回答