二つの主要な困難は
- 暗黙のは、コンパイラによって解決される問題で見ることができます。抽象型を持っているが具体的な意味を必要とする場所では、事前定義された型クラスインスタンスを結果コードに何とか持ちこたえなければなりません。
- サブタイプを抽象化することは、タイプライクな抽象化をひどく使います。これらを組み合わせるには多くの妥協点と回避策が必要です。
しかし、我々は我々は、おそらく解決暗黙の維持のためにいくつかのデータ型を作成することができ、この
trait Bar[+I] {def doSomething[J >: I](x: J): String}
object Doer {
def apply[I <: Foo](el: I)(implicit ev: Bar[I]) = ev.doSomething(el)
}
trait Foo
case class A() extends Foo
object A {
implicit object Something extends Bar[A] {
def doSomething[X >: A](el: X) = "do A"
}
}
case class B() extends Foo
object B {
implicit object SomethingElse extends Bar[B] {
def doSomething[X >: B](el: X) = "do B"
}
}
のような定義を持っている想像してみましょう:今、あなたは
val xs: List[MemoTC[Foo, Bar]] = List(MemoTC(A()), MemoTC(B()))
xs.map(x => x.withTC(x ⇒ implicit bar ⇒ Doer(x)))
のような奇妙なコードを書くことができ
case class MemoTC[+Value, TC[+_]](value: Value)(implicit tc: TC[Value]) {
def withTC[Result](action: (Value) ⇒ TC[Value] ⇒ Result): Result =
action(value)(tc)
}
を
よろしくお願いしますこの例は、存在型の助けを借りて適合させることもできる:
trait Bar[I] {def doSomething(x: I): String}
object Doer {
def apply[I <: Foo](el: I)(implicit ev: Bar[I]) = ev.doSomething(el)
}
trait Foo
case class A() extends Foo
object A {
implicit object Something extends Bar[A] {
def doSomething(el: A) = "do A"
}
}
case class B() extends Foo
object B {
implicit object SomethingElse extends Bar[B] {
def doSomething(el: B) = "do B"
}
}
abstract class MemoTC[Abstract, TC[_]] {
type Concrete <: Abstract
val value: Concrete
val inst: TC[Concrete]
def withTC[Result](action: (Concrete) ⇒ TC[Concrete] ⇒ Result): Result =
action(value)(inst)
}
object MemoTC {
def apply[A, C <: A, TC[_]](v: C)(implicit tc: TC[C]) = new MemoTC[A, TC] {
type Concrete = C
val value = v
val inst = tc
}
}
val xs: List[MemoTC[Foo, Bar]] = List(MemoTC(A()), MemoTC(B()))
xs.map(x => x.withTC(x ⇒ implicit bar ⇒ Doer(x)))