Проблемы с выводом типа скалы на работу

Общая цель:

Предположим, к примеру, я хочу разработать очень подключаемый трекер проблем. Его базовая реализация может поддерживать только идентификатор заявки и описание. Другие расширения могут добавлять поддержку для других полей, но эти поля могут существовать в базе данных в той же таблице. Даже если это не так, количество запросов к базе данных не должно увеличиваться вместе с количеством расширений. Они должны иметь возможность внести свой вклад в определение запроса.

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)
Другие вопросы по тегам