1

foo1 が失敗し、foo2 が成功するのはなぜですか? コンパイラは Blah のすべてのスーパータイプを自動的にチェックするべきではありませんか?

trait Foo[A] {
  def bar: A
}

trait Bleh;
case class Blah extends Bleh;
implicit object BlehFoo extends Foo[Bleh]

def foo1[A:Foo](a:A) = a

def foo2[A,B:Foo](a:A)(implicit aToB: A => B) = aToB(a)

// Shouldn't it automatically use Bleh?
foo1(Blah())
// Failure: could not find implicit value for evidence parameter of type Foo[Blah]

foo2(Blah())
// Success: Bleh = Blah()
4

1 に答える 1

6

は ではないためFoo[Bleh]、使用できません。として使用するには、反変を onにする必要があります。Foo[Blah]Foo[Bleh]Foo[Blah]FooAFoo[Bleh]Foo[Blah]

trait Foo[-A] {
  def bar(a: A) = println(a) // to make Foo contravariant 
}

これはうまくいきます:

scala> foo1(Blah())
res0: Blah = Blah()

元のコードには、質問に対する回答が含まれています。Foo[Bleh]オリジナルを次のように使用できると仮定しましょうFoo[Blah]

def foo1[A:Foo](): A = implicitly[Foo[A]].bar

val b: Blah = foo1[Blah]()

ここFoo[Bleh]で が使用されている場合Bleh、 の結果として得られbarますが、期待していてBlah、 でBlehはありませんBlah

幸いなことに、コンパイラはオリジナルFoo[Bleh]Foo[Blah]次のように使用することを許可しません。

scala> trait Foo[-A] {
     |   def bar: A
     | }
<console>:8: error: contravariant type A occurs in covariant position in type => A of method bar
         def bar: A
             ^

型推論

これはうまくいきます:

foo1[Bleh](Blah())

ただし、コンパイラはAここで型パラメーターを として推論しませんBleh。「なぜ」を理解するには、次のA:Foo意味を理解する必要があります。

def foo1[A:Foo](a:A) = a // syntax sugar
def foo1[A](a:A)(implicit ev: Foo[A]) = a // same method

A:Foo追加の暗黙的なパラメーターの構文シュガーです。

2 つのパラメーター グループがある場合、コンパイラは最初のグループの型を推測し、その型が既知であると見なします。そのため、最初のパラメーター グループ(a:A)の型Blahが既知であり、2 番目のパラメーター グループが型パラメーターに影響を与えることはできません。

于 2013-08-09T13:57:57.440 に答える