簡単な例を次に示します。
trait Base {
type Out
def v: Out
}
object Base {
type Aux[T] = Base { type Out = T }
class ForH() extends Base {
type Out = HNil
override def v: Out = HNil
}
object ForH extends ForH
}
class TypeClass[B]
trait TypeClassLevel1 {
def summon[B](b: B)(implicit ev: TypeClass[B]): TypeClass[B] = ev
}
object TypeClass extends TypeClassLevel1 {
implicit def t1: TypeClass[Base.Aux[HNil]] = new TypeClass[Base.Aux[HNil]]
implicit def t2: TypeClass[Int] = new TypeClass[Int]
}
it("No Aux") {
val v = 2
TypeClass.summon(v) // works
}
it("Aux") {
val v = new Base.ForH()
TypeClass.summon(v) // oops
TypeClass.summon(Base.ForH) // oops
val v2 = new Base.ForH(): Base.Aux[HNil]
TypeClass.summon(v2) // works!
}
オブジェクト Base/ForH には明らかに安定したパスがあります。これにより、コンパイラが type を解決できない可能性がなくなりますForH.Out
。
私を悩ませているのは、コンパイラがForH <:< Aux[HNil]
. IMHO 両方の機能 (型ラムダと型クラス) は関数型プログラミングの重要な側面ですが、なぜ同時に連携できないのでしょうか?
コンパイラの設計に精通している場合は、追加の質問があります。それを実現するために型クラス検索アルゴリズムを改善するには何が必要ですか? ご意見ありがとうございます。
更新 1 : 特定の修正が提案されましたが、それを一般化しようとして別の問題があります。「 In scala, how to make type class working for Aux pattern?」を参照してください。-詳細はパート 2