假设我想开发一个非常可插入的问题跟踪器。其核心实现可能仅支持票证ID和描述。其他扩展可能会添加对其他各个字段的支持,但这些字段可能存在于同一个表的数据库中。即使不是,对数据库的查询数量也不需要随着扩展数量的增加而增加。他们应该能够为查询的定义做出贡献。
Item[A, B, R[_]]
代表一个列,其中A
表示类型(具有列表示),B
作为数据类型,R
作为类型构造函数表示B
类型的列。因此,R[B]
可能是ScalaQuery的NamedColumn[String]
,例如。
现在我正在尝试创建一个类型类来处理构建"查询"。
以val q开头的行(在结尾处)应该只读取val q = query(items)
并仍然编译。由于defaultNext
推断B0
和/或B
到Nothing
,各种尝试都会产生错误,推断类型参数不符合预期的类型参数,或者a"分歧隐含扩张"错误或其他错误。我认为隐式错误是由不正确的类型推断引发的。
我已经浪费了相当多的时间(这是我的一个开源项目)所以,如果有人可以帮助我,我真的很感激。
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))
答案 0 :(得分:1)
在G-d的帮助下,包括Josh Seureth的一些见解和建议,我得到了它的工作:
trait Item[A] {
type B
type R[_]
def get: A => R[B]
}
object Item {
def apply[A, B, R[_]](get: A => R[B])(render: B => String => String) = {
val get0 = get
type B0 = B
type R0[T] = R[T]
new FirstItem[A] {
type B = B0
type R[T] = R0[T]
def get = get0
}
}
}
trait FirstItem[A] extends Item[A] {
type B
def get: A => R[B]
def &(item: Item[A]) =
new NextItem[A] {
type P = FirstItem.this.type
type B = item.B
type R[T] = item.R[T]
val prev = FirstItem.this: FirstItem.this.type
def get = item.get
}
}
trait NextItem[A] extends Item[A] {
type B
type P <: Item[A]
type _P = P
val prev: P
def get: A => R[B]
def &(item: Item[A]) =
new NextItem[A] {
type P = NextItem.this.type
type B = item.B
type R[T] = item.R[T]
val prev = NextItem.this: NextItem.this.type
def get = item.get
}
}
class CanBuildQuery[A, +Q, -I](val apply: I => A => Q)
class CanBuildQueryImplicits {
def apply[A, ]
implicit def defaultNext[A, I <: NextItem[A], PQ](implicit cbq: CanBuildQuery[A, PQ, I#P]): CanBuildQuery[A, (PQ, I#R[I#B]), I] =
new CanBuildQuery[A, (PQ, I#R[I#B]), I](ni => a => query(ni.prev)(cbq)(a) -> ni.get(a).asInstanceOf[I#R[I#B]])
implicit def defaultFirst[A, B, I <: FirstItem[A]]: CanBuildQuery[A, I#R[I#B], I] =
new CanBuildQuery[A, I#R[I#B], I](i => i.get.asInstanceOf[A => I#R[I#B]])
}
def query[A, Q, I <: Item[A]](i: I with Item[A])(implicit cbq: CanBuildQuery[A, Q, I]): A => Q = cbq apply i
}
val items =
Item((_: Field.type).id)(x => _ + " " + x) &
Item((_: Field.type).name)(x => _ + " " + x) &
Item((_: Field.type).allowMultiple)(x => _ + " " + x)
val q = query(items) apply Field
println(q)