Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
应用Scala函数时,对类型不匹配感到困惑1_Scala_Type Mismatch - Fatal编程技术网

应用Scala函数时,对类型不匹配感到困惑1

应用Scala函数时,对类型不匹配感到困惑1,scala,type-mismatch,Scala,Type Mismatch,以下内容无法使用Scala 2.11.4编译: trait Test { type A type F = Function1[A, String] } trait Util[T <: Test] { def compute1( f: T#A => String, a: T#A ): String = f(a) def compute2( f: T#F, a: T#A ): String = f(a) //

以下内容无法使用Scala 2.11.4编译:

trait Test {
  type A
  type F = Function1[A, String]
}

trait Util[T <: Test] {
  def compute1( f: T#A => String, a: T#A ): String = f(a)
  def compute2( f: T#F, a: T#A ): String = f(a)
  //                                         ^
}
我希望compute1和compute2中的两个f参数具有相同的类型;显然不是

发生什么事了

正如@Eugene和@Zim Zam回答的,这里的问题是由于Scala的路径依赖类型。根据他们的建议,我提出了几个备选方案:

trait Test {
  type A
  type Fa = Function1[A, String]       // original question
  type Fb = Function1[Test#A, String]  // Zim-Zam's suggestion
}

trait TestOps[T <: Test] {
  type G = Function1[T#A, String]
}

trait Util[T <: Test] {
  def compute1( f: T#A => String, a: T#A ): String = f(a)
  // def compute2a( f: T#Fa, a: T#A ): String = f(a)
  // type mismatch; found : a.type (with underlying type T#A) required: _1536.A
  def compute2b( f: T#Fb, a: T#A ): String = f(a)
}

trait Util1 {  
  def compute3a(t: Test)( f: t.Fa, a: t.A ): String = f(a)
  def compute3b(t: Test)( f: t.Fb, a: t.A ): String = f(a)
}

trait Util2[T <: Test] { tops: TestOps[T] =>
  // def compute4a( f: T#Fa, a: T#A ): String = f(a)
  // type mismatch; found : a.type (with underlying type T#A) required: _1642.A
  def compute4b( f: T#Fb, a: T#A ): String = f(a)
  def compute5( f: tops.G, a: T#A ): String = f(a)
}
结果如下:

trait UtilU extends Util[TestU] {
  def get1( f: TestU#A => String, a: TestU#A) = compute1(f, a)
  // def get2b( f: TestU#A => String, a: TestU#A) = compute2b(f, a)
  // type mismatch; found : A.U ⇒ String required: A.Test#A ⇒ String
}

trait UtilU1 extends Util1 {
  val u = new TestU()
  def get3a( f: u.A => String, a: u.A) = compute3a(u)(f, a)
  // def get3b( f: u.A => String, a: u.A) = compute3b(u)(f, a)
  // type mismatch; 
  // found : UtilU1.this.u.A ⇒ String (which expands to) A.U ⇒ String 
  // required: UtilU1.this.u.Fb (which expands to) A.Test#A ⇒ String
}

class UtilU2 extends Util2[TestU] with TestOps[TestU] {
  // def get4b( f: TestU#A => String, a: TestU#A) = compute4b(f, a)
  // type mismatch; found : A.U ⇒ String required: A.Test#A ⇒ String
  def get5( f: TestU#A => String, a: TestU#A) = compute5(f, a)
}
因此,我们只剩下3个合理的变化:

compute1
(无函数1类型别名)
compute3a
compute5

对于别名函数1类型,我们只有两种选择:
compute3a
compute5


描述它们之间差异的正确方法是什么?

这是因为路径依赖类型在scala中的实现方式不同

val test1 = new Test {}
val test2 = new Test {}
// test1.A is different type from test2.A
在您的示例中,您基本上是说f和a可以从不同的测试实例中传递,在这种情况下,在第一个参数的类型f中使用的a将不同于第二个参数

但是如果你把它限制在T的某个实例中,它就会编译

def compute2(t: T)( f: t.F, a: t.A ): String = f(a)
Upd
然而,compute1仍然应该是这样的

@Eugene认为这是由路径依赖类型引起的是正确的-您可以用

trait Test {
  type A
  type F = Function1[Test#A, String]
}

现在
F
可以将任何
A
作为其参数

另一个选项是在UtilThanks@Zim Zam中为建议定义F。但是,这种方法在定义特性测试的专门化时会产生问题,因为函数参数的类型在Scala中是反向的。感谢@Eugene的解释(路径依赖类型)。这种方法似乎不切实际,因为我必须将T的一个实例作为一个不能隐式的参数传递。
def compute2(t: T)( f: t.F, a: t.A ): String = f(a)
trait Test {
  type A
  type F = Function1[Test#A, String]
}