Scala 当类型已知时,为什么对重载定义的引用不明确?

Scala 当类型已知时,为什么对重载定义的引用不明确?,scala,compiler-construction,Scala,Compiler Construction,我有这样一个函数: def ifSome[B, _](pairs:(Option[B], B => _)*) { for((paramOption, setFunc) <- pairs) for(someParam <- paramOption) setFunc(someParam) } 然后,以下行生成一个错误: ifSome(Option("hi") -> f.setB _) <console>:11: error: ambiguous r

我有这样一个函数:

def ifSome[B, _](pairs:(Option[B], B => _)*) {
  for((paramOption, setFunc) <- pairs)
    for(someParam <- paramOption) setFunc(someParam)
}
然后,以下行生成一个错误:

ifSome(Option("hi") -> f.setB _)

<console>:11: error: ambiguous reference to overloaded definition,
both method setB in class Foo of type (b: Int)Unit
and  method setB in class Foo of type (b: String)Unit
match expected type ?
                 ifSome(Option("hi") -> f.setB _)

但是我想理解为什么这是必要的。

Scala中的类型推断只能从一个参数列表到下一个参数列表。由于您的
ifSome
只有一个参数列表,Scala不会推断任何东西。您可以按如下方式更改ifSome:

def ifSome[B, _](opts:Option[B]*)(funs: (B => _)*) {
  val pairs = opts.zip(funs)
  for((paramOption, setFunc) <- pairs)
    for(someParam <- paramOption) setFunc(someParam)
}
并相应地将调用更改为
ifSome

ifSome(Option("hi"))(f.setB _)

这一切都很有效。当然,现在您必须检查
opts
funs
在运行时是否具有相同的长度。

您需要尝试
$scalac-Ydebug-Yinfer debug x.scala
,但首先您需要最小化

在本例中,您将看到在当前版本中,B是如何在第一个参数列表中求解的:

[infer method] solving for B in (bs: B*)(bfs: Function1[B, _]*)Nothing 
based on (String)(bfs: Function1[B, _]*)Nothing (solved: B=String)
对于未结婚的版本,你会看到一些奇怪的地方

[infer view] <empty> with pt=String => Int

正如我在回答中所解释的,类型推断(计算出B是字符串)可以从一个参数列表工作到下一个参数列表。这是关于参数列表的。感谢第二种解决方法,但我仍然不明白为什么有必要这么做。另外,你能解释一下你的例子中推断出了什么,我的例子中没有推断出什么吗?据我所知,我希望编译器能够从Foo中可用的类型推断出调用站点中选项的类型。更改ifSome的参数列表如何向编译器提供更多关于Foo中可用类型的信息?实际上,我想我正在接近理解。您的意思是,编译器不会检查选项[B]中的类型B是否与B=>\中的类型B匹配,因为它们位于同一个参数列表中,但如果将它们放在单独的列表中,编译器将进行检查并使用该信息从Foo中选择正确的函数。但这似乎也不对,因为如果我执行
ifSome(选项(1)->((x:String)=>x+“test”)
编译器会注意到我在B上有一个类型不匹配。如果编译器可以检查以注意到不匹配,为什么它不能选择正确的函数呢?是的,这就是我要说的。我不熟悉编译器的内部结构,所以我无法解释为什么它有这个限制,或者为什么它不能很容易地被删除。
ifSome(Option("hi"))(f.setB _)
[infer method] solving for B in (bs: B*)(bfs: Function1[B, _]*)Nothing 
based on (String)(bfs: Function1[B, _]*)Nothing (solved: B=String)
[infer view] <empty> with pt=String => Int
object Test extends App {
  def f[B](pairs: (B, B => _)*) = ???
  def f2[B](bs: B*)(bfs: (B => _)*) = ???

  def g(b: String) = ???
  def g(b: Int) = ???

  // explicitly
  f[String](Pair("hi", g _))

  // solves for B in first ps
  f2("hi")(g _)

  // using Pair instead of arrow means less debug output
  //f(Pair("hi", g _))

  locally {
    // unused, but selects g(String) and solves B=String
    import language.implicitConversions
    implicit def cnv1(v: String): Int = ???
    f(Pair("hi", g _))
  }

  // a more heavy-handed way to fix the type
  class P[A](a: A, fnc: A => _)
  class PS(a: String, fnc: String => _) extends P[String](a, fnc)
  def p[A](ps: P[A]*) = ???
  p(new PS("hi", g _))
}