4

scala 2.10.0-M7 を使用した次のセッションでは:

scala> trait A
defined trait A
scala> class B extends A
defined class B
scala> class C extends A
defined class C
scala> Some(0).fold(new B){_=>new C}
<console>:11: error: type mismatch;
 found   : C
 required: B
              Some(0).fold(new B){_=>new C}

私は、コンパイラが不平を言うのではなく、共通のスーパータイプ (つまり A) を見つけることを期待しています。それは一般的な型推論の制限ですか、それとも Option.fold の定義方法の結果ですか?

ありがとうございました。

4

3 に答える 3

10

Option.foldこの問題は、Scalas の型推論アルゴリズムとその定義方法の組み合わせの結果です。

Scalas の型推論は左から右に機能します。これは、式の可能な型を検索するために左端のシンボルから開始することを意味します。さらに、メソッド パラメーター リストの場合、これはジェネリック型が左端のパラメーター リストによって埋められた型にバインドされることを意味します。

scala> def meth[A](a1: A, a2: A) = (a1, a2)
meth: [A](a1: A, a2: A)(A, A)

scala> meth(1, "")
res7: (Any, Any) = (1,"")

scala> def meth[A](a1: A)(a2: A) = (a1, a2)
meth: [A](a1: A)(a2: A)(A, A)

scala> meth(1)("")
<console>:10: error: type mismatch;
 found   : String("")
 required: Int
              meth(1)("")
                      ^

ご覧のとおり、最初のケースAnyでは が推論されますが、2 番目のケースでは、 の型がA最初のパラメーター リストによってバインドされ、2 番目のケースではそれ以上変更できないため、コンパイラ エラーがスローされます。

ただし、問題のメソッド呼び出しを機能させるために、結果の型はOption、2 番目のパラメーター リストに到達するまで定義されない場合があります。これには右から左への型推論が必要なため、エラーが発生します。これは次のものと多少同じですList.fold:

scala> List(1).foldLeft(Nil)((xs,x) => x::xs)
<console>:8: error: type mismatch;
 found   : List[Int]
 required: scala.collection.immutable.Nil.type
              List(1).foldLeft(Nil)((xs,x) => x::xs)
                                               ^

コードを機能させるには、結果のコレクションのタイプを明示的に指定する必要があります。例については@rks の回答を参照してください。

定義されているように定義されている理由の完全な説明については、ここでの議論を参照してください。要するにOption、多くの点でコレクションの設計に従います。したがって、コレクションと同じように動作する場合はより明確になります。

于 2012-09-07T15:36:03.773 に答える
2

これは、型推論アルゴリズムの一般的な制限です。リスト間の折りたたみにも同じ制限があります。Scalaでのプログラミングを引用するには:

flattenの両方のバージョンでは、フォールドの開始値である空のリストにタイプ注釈が必要であることに注意してください。これは、リストの正しい型を自動的に推論できないScalaの型推論器の制限によるものです。

Scalaの型推論アルゴリズムは、複数のパラメーターリストを持つメソッド間で段階的に機能します。最初に指定されたタイプは、2番目、2番目は3番目などの推論に使用できます。スタイルガイドで概説されているfoldように、推論エンジンはリストのタイプを認識しているため、関数でより単純な構文を使用できます。最初の引数リストからのアキュムレータのタイプ。

ただし、連続するパラメーターリスト間で段階的に機能するため、関数の引数の型をに推論した後、推論エンジンは戻って戻り型(アキュムレーター型と同じ)を更新しませんfold。代わりに、タイプエラーが発生します。

上記の例では、アキュムレータ値に型アノテーションを付けるだけで、次のようになります。

Some(0).fold(new B: A){_=>new C}
于 2012-09-07T16:02:20.087 に答える
2

sschaef版では精度が足りないような気がします。scala についてはよくわかりませんが (実際、使用したことはありません)、関数の実装方法に依存するものではないと思います。また、「タイパーは左から右に移動する」ということも理解していませんでした。

最近のバージョンの Scala を持っていないので、あなたのサンプル venechka でテストすることはできませんが、いくつかの型注釈を追加することで、入力エラー/制限を回避できると思います。たとえば、sschaef の例を次に示します。

scala> List(1).foldLeft(Nil)((xs,x) => x::xs)
<console>:8: error: type mismatch;
 found   : List[Int]
 required: scala.collection.immutable.Nil.type
              List(1).foldLeft(Nil)((xs,x) => x::xs)
                                               ^

scala> List(1).foldLeft(Nil : List[Int])((xs,x) => x::xs)
res1: List[Int] = List(1)

そして、次のようなことを行うことで、あなたの例で同じことができると思います:

Some(0).fold(new B : A){_=>new C}

繰り返しますが、これは Scala typer の制限 (おそらくサブタイピングの存在によるもの) だと思いますが、それを強く断言する前に周りを見回す必要があります。

とにかく、あちこちに型注釈を追加するとうまくいくはずなので、楽しんでください!

編集:ああ、sschaefは彼の答えを編集して、この動作の理由について私が言っていることをおそらく無効にするいくつかの説明をしました。しかし、型注釈が問題を解決するという事実は変わりません。したがって、このメッセージをそのままにしておきます。

于 2012-09-07T16:00:40.590 に答える