问题描述
例如,假设我要开发一个非常可插拔的问题跟踪器.它的核心实现可能仅支持票证ID和描述.其他扩展可能会增加对其他各个字段的支持,但是这些字段可能存在于同一表的数据库中.即使没有,对数据库的查询数量也不必随扩展数量的增加而增加.他们应该能够为查询的定义做出贡献.
Suppose for instance I want to develop a very pluggable issue tracker. Its core implementation might only support a ticket id and a description. Other extensions might add support for various other fields, yet those fields might exist in the database on the same table. Even if not, the number of queries to the database should not need to increase along with the number of extensions. They should be able to contribute to the definition of the query.
Item[A, B, R[_]]
将表示一列,其中A
是表类型(具有列表示形式),B
是数据类型,而R
是类型构造函数,表示类型为B
的列.因此,例如R[B]
可能是ScalaQuery的NamedColumn[String]
.
Item[A, B, R[_]]
would represent a column, with A
for the table type (has the column representations), B
as the data type, and R
as the type constructor representing a column of type B
. So R[B]
might be ScalaQuery's NamedColumn[String]
, for example.
现在,我正在尝试创建一个类型类来处理构建查询".
Right now I'm trying to make a typeclass to handle building the "query".
以val q开头的行(末尾)应简单阅读val q = query(items)
并仍可编译.由于defaultNext
推断B0
和/或B
到Nothing
,各种尝试都会产生一个推断的类型参数与预期的类型参数不一致的错误,或者是发散的隐式扩展"错误,或者其他错误.我认为隐式错误是由错误的类型推断触发的.
The line starting with val q (at the end) should read simply val q = query(items)
and still compile. Various attempts yield either an error that inferred type arguments don't conform to expected type arguments, due to defaultNext
inferring B0
and/or B
to Nothing
, or a "diverging implicit expansion" error, or other errors. I think the implicit error is triggered by incorrect type inference though.
我已经在此上浪费了好几天(这是我的一个开源项目),所以如果有人可以帮忙,我将非常感激.
I've already wasted quite a few days on this (it's for an open-source project of mine) so if someone could kindly help out I would really really appreciate it.
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))
推荐答案
在G-d的帮助下,包括乔什·塞里斯(Josh Seureth)的一些见解和建议,我使它可以工作:
With G-d's help, including some insights and suggestions from Josh Seureth, I got it to work:
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)
这篇关于无法获取Scala类型推断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!