一般的な目標:
たとえば、非常にプラグ可能な課題トラッカーを開発したいとします。そのコア実装は、チケット ID と説明のみをサポートする場合があります。他の拡張機能は、他のさまざまなフィールドのサポートを追加する可能性がありますが、それらのフィールドは同じテーブルのデータベースに存在する可能性があります。そうでない場合でも、データベースへのクエリの数は、拡張機能の数とともに増加する必要はありません。クエリの定義に貢献できる必要があります。
Item[A, B, R[_]]
はA
、テーブル型 (列表現を持つ) をB
データ型R
として、型コンストラクターとして type の列を表す列を表しますB
。たとえば、R[B]
ScalaQuery の もそうかもしれません。NamedColumn[String]
現在、「クエリ」の構築を処理する型クラスを作成しようとしています。
問題:
(最後にある) val q で始まる行は、単純val q = query(items)
に読み取ってコンパイルする必要があります。さまざまな試みにより、defaultNext
推論B0
された型引数が期待される型引数に準拠していないというエラーが発生します。ただし、暗黙的なエラーは、間違った型推論によって引き起こされると思います。B
Nothing
私はすでにこれにかなりの日数を費やしてきました (これは私のオープンソース プロジェクトのためです)。
class CanBuildQuery[A, B, R[_], Q, I <: Item[A, B, R]](val apply: I => A => Q)
trait Low {
implicit def defaultNext[A, B, R[_], B0, P <: Item[A, B0, R], I <: NextItem[A, B, B0, R, P], PQ](
implicit cbq: CanBuildQuery[A, B0, R, PQ, P]
): CanBuildQuery[A, B, R, (PQ, R[B]), I] =
new CanBuildQuery[A, B, R, (PQ, R[B]), I](sys.error("todo"))
}
object CanBuildQuery extends Low {
implicit def defaultFirst[A, B, R[_]]:
CanBuildQuery[A, B, R, R[B], FirstItem[A, B, R]] =
new CanBuildQuery[A, B, R, R[B], FirstItem[A, B, R]](_.get)
}
def query[A, B, R[_], Q, I <: Item[A, B, R]](
i: I with Item[A, B, R]
)(
implicit cbq: CanBuildQuery[A, B, R, Q, I]
): A => Q =
cbq apply i
trait Item[A, B, +R[_]] {
def get: A => R[B]
}
trait FirstItem[A, B, +R[_]] extends Item[A, B, R] {
def get: A => R[B]
}
trait NextItem[A, B, B0, +R[_], I <: Item[A, B0, R]] extends Item[A, B, R] {
val prev: I
def get: A => R[B]
}
val items =
new NextItem[Boolean, String, Long, Option, FirstItem[Boolean, Long, Option]]{
val get = { _:Boolean => "hello" }
val prev = new FirstItem[Boolean, Long, Option] {
val get = { _:Boolean => 73 }
}
}
val q = query(items)(CanBuildQuery.defaultNext(CanBuildQuery.defaultFirst))