15

Scalaで型クラスパターンを使用していると仮定します。クラスCを型クラスFooの一部にする方法は次のとおりです。

Welcome to Scala version 2.9.0.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_26).

scala> trait Foo[T] { def foo(t: T) }
defined trait Foo

scala> def foo[T : Foo](t: T) { implicitly[Foo[T]].foo(t) }
foo: [T](t: T)(implicit evidence$1: Foo[T])Unit

scala> class C
defined class C

scala> foo(new C)
<console>:11: error: could not find implicit value for evidence parameter of type Foo[C]
       foo(new C)
          ^

scala> implicit object FooC extends Foo[C] { override def foo(c: C) { println("it's a C!") } }
defined module FooC

scala> foo(new C)
it's a C!

ここまでは順調ですね。しかし、CのサブクラスDがあり、Dのインスタンスも型クラスの「中に」入れたいとします。

scala> class D extends C
defined class D

scala> foo(new D)
<console>:13: error: could not find implicit value for evidence parameter of type Foo[D]
       foo(new D)
          ^

ドー!Dの型クラスインスタンスを明示的に提供せずにこれを機能させるにはどうすればよいですか?

4

1 に答える 1

16

これには、Cのみの問題を修正するか、型クラス全体の問題を修正するかによって、さまざまな解決策が考えられます。

Cの場合のみ、次のようにimplicit object FooC ...言います。

implicit def CIsFoo[T <: C]: Foo[T] =
  new Foo[T] { override def foo(t: T) { println("it's a C!") } }

Fooをすべて修正するには、反変にします。

trait Foo[-T] { def foo(t: T) }

または、何らかの理由でそれができない、またはしたくない場合は、次のように置き換えることができますdef foo...

def foo[T](t: T)(implicit foo: Foo[_ >: T]) =
  foo.foo(t)

(#scalaの住人であるDanielSobralとStefanZeigerの助けに感謝します。)

2011年9月20日更新され、「Fooを反変にする」ソリューションが含まれるようになりました。

于 2011-07-13T17:15:56.713 に答える