无法让scala类型推断工作

时间:2012-07-10 06:53:10

标签: scala implicits

总目标:

假设我想开发一个非常可插入的问题跟踪器。其核心实现可能仅支持票证ID和描述。其他扩展可能会添加对其他各个字段的支持,但这些字段可能存在于同一个表的数据库中。即使不是,对数据库的查询数量也不需要随着扩展数量的增加而增加。他们应该能够为查询的定义做出贡献。

Item[A, B, R[_]]代表一个列,其中A表示类型(具有列表示),B作为数据类型,R作为类型构造函数表示B类型的列。因此,R[B]可能是ScalaQuery的NamedColumn[String],例如。

现在我正在尝试创建一个类型类来处理构建"查询"。

问题:

以val q开头的行(在结尾处)应该只读取val q = query(items)并仍然编译。由于defaultNext推断B0和/或BNothing,各种尝试都会产生错误,推断类型参数不符合预期的类型参数,或者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))

1 个答案:

答案 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)