4

私は次のような機能を持っています:

def ifSome[B, _](pairs:(Option[B], B => _)*) {
  for((paramOption, setFunc) <- pairs)
    for(someParam <- paramOption) setFunc(someParam)
}

そして、次のようなオーバーロードされた関数:

class Foo{ 
  var b=""
  def setB(b:String){this.b = b}
  def setB(b:Int){this.b = b.toString}
}

val f = new Foo

次に、次の行でエラーが発生します。

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 _)

しかし、コンパイラは私たちが Function1[java.lang.String, _] を探していることを認識しています。何か不足していますか、それともコンパイラのバグですか (または、機能のリクエストである可能性があります)?

このような型注釈を使用して、これを回避できました

ifSome(Option("hi") -> (f.setB _:String=>Unit))

しかし、なぜこれが必要なのかを理解したいと思います。

4

2 に答える 2

2

試してみたいと思うでしょう$ 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

オーバーロードを明確にしようとするため、以下の奇妙な解決策につながる可能性があります。

ダミーの Implicit は、オーバーロードを解決して推論を続行できるようにするという唯一の目的を果たします。暗黙的な自体は使用されておらず、未実装のままです???

これはかなり奇妙な解決策ですが、過負荷は悪であることはご存知ですよね? そして、自由に使えるあらゆるツールを使って悪と戦わなければなりません。

また、型注釈の回避策は、通常の方法で型パラメーターを指定するよりも面倒であることも確認してください。

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 _))
}
于 2012-09-29T05:13:24.140 に答える
2

Scala での型推論は、あるパラメーターリストから次のパラメーター リストにのみ機能します。ifSomeパラメータ リストが 1 つしかないため、Scala は何も推論しません。ifSome次のように変更できます。

def ifSome[B, _](opts:Option[B]*)(funs: (B => _)*) {
  val pairs = opts.zip(funs)
  for((paramOption, setFunc) <- pairs)
    for(someParam <- paramOption) setFunc(someParam)
}

ふーちゃんはそのままで…

class Foo{ 
  var b=""
  def setB(b:String){this.b = b}
  def setB(b:Int){this.b = b.toString}
}

val f = new Foo

ifSomeそれに応じて呼び出しを変更します。

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

そして、それはすべて機能します。もちろん、実行時に同じ長さであるかどうかを確認する必要がありoptsます。funs

于 2012-09-28T22:34:31.760 に答える