gpt4 book ai didi

scala - Scala 中类值内的路径依赖类型

转载 作者:行者123 更新时间:2023-12-02 00:09:30 26 4
gpt4 key购买 nike

我想将具有抽象类型的类型的值赋予类,然后使用它的路径相关类型。看下面的例子(使用 Scala 2.10.1):

trait Foo {
type A
def makeA: A
def useA(a: A): Unit
}

object Test {

class IntFoo extends Foo {
type A = Int
def makeA = 1
def useA(a: Int) = println(a)
}

class FooWrap(val a: Foo) {
def wrapUse(v: a.A) = a.useA(v)
}

val foo = new IntFoo

/* Path dependent locally */
val bar = foo
bar.useA(foo.makeA) // works

/* Path dependent through class value */
val fooWrap = new FooWrap(foo)

fooWrap.a.useA(foo.makeA) // fails
// error: type mismatch; found : Int required: Test.fooWrap.a.A

fooWrap.wrapUse(foo.makeA) // fails
// error: type mismatch; found : Int required: Test.fooWrap.a.A

}

首先,我不明白本地和类值情况(注意公共(public)的、不可变的值)之间的根本区别以及类型检查失败的原因(因为显然 Test.fooWrap.a.A =:= foo .A).这是 Scala 编译器的限制吗?

其次,我怎样才能实现我想做的事情?

更新

这似乎可以通过使用泛型和内联类型约束来实现:

class FooWrap[T](val a: Foo { type A = T }) {
def wrapUse(v: T) = a.useA(v)
}

但是,在我的例子中,A 实际上是一个更高级的类型,所以这个例子变成了:

trait Foo {
type A[T]
def makeA[T]: A[T]
def useA(a: A[_]): Unit
}

object Test {

class OptFoo extends Foo {
type A[T] = Option[T]
def makeA[T] = None
def useA(a: A[_]) = println(a.get)
}

class FooWrap(val a: Foo) {
def wrapUse(v: a.A[_]) = a.useA(v)
}

val foo = new OptFoo

/* Path dependent locally (snip) */

/* Path dependent through class value */
val fooWrap = new FooWrap(foo)

fooWrap.a.useA(foo.makeA) // fails
// polymorphic expression cannot be instantiated to expected type;
// found : [T]None.type required: Test.fooWrap.a.A[_]

fooWrap.wrapUse(foo.makeA) // fails
// polymorphic expression cannot be instantiated to expected type;
// found : [T]None.type required: Test.fooWrap.a.A[_]

}

最佳答案

在您原来的问题中,您的问题是 Scala 编译器无法证明 foo.makeA 的结果类型相等。参数类型为 fooWrap.a.useA .为此,它需要能够证明 foo 的身份。与 fooWrap.a我们可以直观地看到这里一定是这种情况,但编译器无法直接跟踪。

有几种方法可以解决这个问题。首先,您可以使用 fooWrap.a统一代替foo ,

scala> fooWrap.a.useA(fooWrap.a.makeA)
1

现在,编译器很容易将 A 的前缀 ( fooWrap.a) 识别为在两次出现时相同。

其次,您可以参数化 FooWrap以捕获其 Foo 类型的方式更准确地说,

scala> class FooWrap[F <: Foo](val a: F) {
| def wrapUse(v: a.A) = a.useA(v)
| }
defined class FooWrap

scala> val fooWrap = new FooWrap(foo)
fooWrap: FooWrap[IntFoo] = FooWrap@6d935671

scala> fooWrap.a.useA(foo.makeA)
1

这里是 FooWrap 的类型参数被推断为 IntFoo而不是光秃秃的Foo ,因此 A已知为 Int , 因为它在 foo.makeA 的结果类型中.

在您的更新中,您引入了一个额外的问题:您更改了 useA 的签名到,

def useA(a: A[_]): Unit

_这是一个存在主义,它将挫败所有诱使编译器证明有用的类型等式的尝试。相反,你需要一些类似的东西,

trait Foo {
type A[T]
def makeA[T]: A[T]
def useA[T](a: A[T]): Unit
}

class OptFoo extends Foo {
type A[T] = Option[T]
def makeA[T]: A[T] = None
def useA[T](a: A[T]) = a map println
}

class FooWrap[F <: Foo](val a: F) {
def wrapUse[T](v: a.A[T]) = a.useA(v)
}

val foo = new OptFoo

示例 REPL session ,

scala> val fooWrap = new FooWrap(foo)
fooWrap: FooWrap[OptFoo] = FooWrap@fcc10a7

scala> fooWrap.a.useA(foo.makeA)

scala>

关于scala - Scala 中类值内的路径依赖类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16180248/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com