首页 文章

依赖类型的工厂方法

提问于
浏览
3

我正在与Scala 2.11.7中的依赖类型进行斗争 . 以下是上下文:

trait Counter {
  type T
  def zero: T
  def incr( t: T ): T
}
object IntCounter extends Counter {
  type T = Int
  val zero = 0
  def incr( t: Int ) = t + 1
}

case class Foo( counter: Counter )

def twice( foo: Foo )( cntr: foo.counter.T ): foo.counter.T =
  foo.counter.incr( foo.counter.incr( cntr ) )

到目前为止一切都那么好,一切都汇编了但是我想添加一个包含 Foo 实例和相应计数器状态的对象 . 例如:

trait Bar {
  val foo: Foo
  val current: foo.counter.T
}

定义没问题(前提是我使用抽象vals) . 但是我无法定义工厂方法(也就是智能构造函数) . 我所有天真的尝试都无法编译 . 例如,定义:

def bar( f: Foo )( cntr: f.counter.T ): Bar = new Bar {
  val foo = f
  val current = cntr
}

无法编译错误:

xxx: overriding value current in trait Bar of type this.foo.counter.T;
value current has incompatible type
   val current = cntr
       ^

如何强制编译器理解这两种类型确实相同?我可以用泛型来解决问题,但如果可能的话,我更愿意避免使用此选项 .

1 回答

  • 3

    如果 barBar 的单个构造函数,您可以像这样解决它:

    sealed trait Foo { //can't be case class because you can't even call `twice` method then
      type Ctr <: Counter
      type Z <: Ctr#T
      val counter: Ctr
    }
    
    def foo[Ct <: Counter](ctr: Ct): Foo{type Ctr = Ct} = new Foo {
      type Ctr = Ct
      type Z = ctr.T
      val counter = ctr
    }
    
    
    sealed trait Bar {
      type Ctrr <: Counter
      type TT <: Counter#T
      val foo: Foo {type Ctr = Ctrr}
      val current: TT
    }
    
    def bar[Ct <: Counter]( f: Foo{type Ctr = Ct} )( cntr: f.counter.T )(implicit ev: Ct =:= f.Ctr): Bar {type Ctrr = Ct; type TT = f.counter.T} = new Bar {
      type Ctrr = Ct
      type TT = f.counter.T 
      val foo = f
      val current = cntr
    }
    

    用法:

    scala> val br = bar(foo(IntCounter))(5)
    br: Bar{type Ctrr = IntCounter.type; type TT = Int} = $anon$1@35267fd4
    
    scala> br.foo.counter.incr(br.current)
    res41: Int = 6
    

    这里的缺点是,无论在哪里创建新的 Foo 实例,都必须在 TTfoo 成员之间指定(并维护)相同的根类型 .

相关问题