scala - 具有依赖类型的工厂方法

标签 scala functional-programming dependent-type path-dependent-type

我在 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
}

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

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
       ^

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

最佳答案

如果 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 成员之间指定(并维护)相同的根类型 实例。

关于scala - 具有依赖类型的工厂方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33303225/

相关文章:

scala - Scala 2.9 中的案例类和代理行为

debugging - 如何在 IntelliJ Idea 中调试 scalatra 应用程序?

scala - 不理解 Scala 分隔延续的类型 (A @cpsParam[B,C])

scala - 循环直到 scala 中满足某个条件

haskell - 如果 applicative 就足够了,为什么序列需要 monad?

haskell - 将存在主义提升到类型层面

agda - 涉及 nat 添加的依赖类型

由回调驱动的 Java/Scala Future

dependent-type - 测试一个类型是否是 Idris 中的函数类型

scala - 使用给定的部分大小列表将 Scala 列表拆分为多个部分。[分区]