2015-09-30 19 views
14

は、我々は機能を持っているとしましょう:F [_]パラメータが有効な場所でIntを渡すのはなぜですか?

def bar[F[_], A](x: F[A], y: F[A]) = null 

以下のすべての行動は明らかです:

bar(List(1, 2, 3), List(1)) // compile ok 
bar(List(1), Some(1)) // doesn't compile 

しかし、

bar(1, List(1)) // compile ok 
bar(1, 1) // compile ok 

なぜ?

P.S.例:FSiS Part 1 - Type Constructors, Functors, and Kind Projector

+4

は両方とも 'Any'と' Nothing'ある種類の多型、参照、例えばだ場合

私は試行錯誤することにより、この動作を知ったが、私は知りません[SI-9248](https://issues.scala-lang.org/browse/SI-9248)。 –

+2

btw 'bar(1、List(1))'は '2.9'ではコンパイルされませんが、' 2.10'ではコンパイルされます。 – dmitry

答えて

4

私は(関係するいくつかの謎がまだあるが)以下は、手掛かりを与えると思う:

def baz[F[_], A](x: F[A]): F[A] = x 

scala> baz("str") 
res5: Comparable[String] = str 

scala> baz(1) 
res6: Any = 1 

scala> class Foo 
defined class Foo 

scala> baz(new Foo) 
<console>:15: error: no type parameters for method baz: (x: F[A])F[A] exist so that it can be applied to arguments (Foo) 
--- because --- 
argument expression's type is not compatible with formal parameter type; 
found : Foo 
required: ?F 
       baz(new Foo) 
      ^
<console>:15: error: type mismatch; 
found : Foo 
required: F[A] 
       baz(new Foo) 
       ^

scala> case class Foo2 
warning: there were 1 deprecation warning(s); re-run with -deprecation for details 
defined class Foo2 

scala> baz(Foo2) 
res10: scala.runtime.AbstractFunction0[Foo2] = Foo2 

だから、機能barbazは、ケースのための文字列、AbstractFunction0ための彼らができる任意のコンテナタイプ(Comparableを見つけていますクラスなど)を使用して、F[_]と一致させます。

推測:Intの場合、基になるバイトコード内の(ボックス化された)プリミティブ型の特殊な「コンテナ」型を使用していると思われます。この特別なタイプがScalaに "Any"としてのみ印刷されることができますが、実際には "Any[_]"と考えることができる特別なタイプです。これがプリミティブの特別な処理と関係していることを裏付けるように、上記の(ケースではない)クラスFooのような非プリミティブな単純な型では失敗することに注意してください。

4

あなたは型推論システムの限界に遭遇していると思います。この上でいくつかの光を当てるために、我々はより多くの有用な出力を取得するには、このビット再定義するときに何が起こるか見てみましょう:最初の例で

class Bar[F[_], A](x: F[A], y: F[A]) {} 
res0: Bar[List,Int] = [email protected] 
new Bar(List(1,2,3), List(1)) 
res1: Bar[Any,Int] = [email protected] 
new Bar(List(1), 1) 
res2: Bar[Any,Int] = [email protected] 
new Bar(List(1), Some(1)) 
<console>:12: error: inferred kinds of the type arguments (Product with java.io.Serializable,Int) do not conform to the expected kinds of the type parameters (type F,type A) in class Bar. 
Product with java.io.Serializable's type parameters do not match type F's expected parameters: 
<refinement of Product with java.io.Serializable> has no type parameters, but type F has one 
     new Bar(List(1), Some(1)) 
    ^
<console>:12: error: type mismatch; 
found : List[Int] 
required: F[A] 
     new Bar(List(1), Some(1)) 
       ^
<console>:12: error: type mismatch; 
found : Some[Int] 
required: F[A] 
     new Bar(List(1), Some(1)) 

を、我々は完璧な理にかなってBar[List, Int]を持って、私たちは、渡されました2つList[Int]

2番目と3番目には、Bar[Any, Int]があります。ここで奇妙なところがあります。 AnyAnyVal(ScalaのJavaプリミティブに相当する親)とAnyRef(JavaのObjectに相当するScala)の親です(詳細はScala Documentationを参照してください)。

Scalaの型推論は、このBarのコンストラクタはAためFためAny、およびIntを受け入れるべきであると決定しました。 Anyは確かにListIntの親ですが、それは問題ありません。 Listは実際には[Int]とパラメータ化されています。 ScalaはIntAny[Int]であると言っても大丈夫です。私はその部分の良い説明がありません。

私は正直なところ混乱しています。これがバグかどうか疑問に思っています。何らかの理由で、ListSomeの両方がAnyの子であり、どちらもIntでパラメータ化されていても、それは許可されません。私はうまくコンパイラの推論方法の複雑さに精通していないよ怖いが、それは価値があるものを、明示的にこれらのパラメータを指定するために働く:私に

new Bar[Any,Int](List(1), Some(1)) 
res14: Bar[Any,Int] = [email protected] 

が、それだけでできる型推論システムを提案しています」型を適切に推論したり、型が正しくないと推定したりします。

3

これは、コンパイラがいくつかの型を推測するために機能します。ここでは、これがbarに追加型で次のようになります。

bar[Any, Int](1, List(1)) // compile ok 
    bar[Any, Nothing](1, 1) // compile ok 

コンパイラはListSomeの両方をサポートするための型を推論することはできませんので、これはbar(List(1), Some(1))のために動作しません。しかし、上記のようにダウンキャストすることができます、bar[Any, Int](List(1), Some(1))作品。

4

種類のシステムと組み合わせてAnyタイプのものが使用されているようです。

Anyはタイプパラメータをとらない: val i:Any[Int] = 1は、単なる種類のものでなければならない。あなたはあなたの例で示したよう

Anybar[Any, Nothing](1,1)

我々は高いkinded位置にAnyを使用する場合は、このタイプのパラメータは、魔法の簡単な種類とになり、高いkinded型が期待されている位置で使用することができますこの以前より上位の種別の型パラメータは完全に無視される。

barの最初の型パラメータは、我々はできるAnyが、2番目のパラメータとして任意のタイプであり、それは常にコンパイルします:

bar[Any,String](List(1),List(2)) 
bar[Any, Boolean](1,2) 
bar[Any, Int](List(), true) 
case class A() 
bar[Any, A](List, A) 

はにいくつかの例をリード型推論に問題があるようです型の注釈なしで失敗します。それはバグや機能;-)

関連する問題