无法获取Scala类型推断 [英] Trouble getting scala type inference to work

查看:83
本文介绍了无法获取Scala类型推断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,假设我要开发一个非常可插拔的问题跟踪器.它的核心实现可能仅支持票证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和/或BNothing,各种尝试都会产生一个推断的类型参数与预期的类型参数不一致的错误,或者是发散的隐式扩展"错误,或者其他错误.我认为隐式错误是由错误的类型推断触发的.

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类型推断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆