Проблемы с выводом типа скалы на работу
Общая цель:
Предположим, к примеру, я хочу разработать очень подключаемый трекер проблем. Его базовая реализация может поддерживать только идентификатор заявки и описание. Другие расширения могут добавлять поддержку для других полей, но эти поля могут существовать в базе данных в той же таблице. Даже если это не так, количество запросов к базе данных не должно увеличиваться вместе с количеством расширений. Они должны иметь возможность внести свой вклад в определение запроса.
Item[A, B, R[_]]
будет представлять столбец, с A
для типа таблицы (имеет представления столбцов), B
в качестве типа данных, и R
как конструктор типа, представляющий столбец типа B
, Так R[B]
может быть ScalaQuery's 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))
1 ответ
С помощью Всевышнего, включая некоторые идеи и предложения от Джоша Сьюрета, я заставил его работать:
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)