Scala高级类型用法

Mar*_*ein 7 types scala shapeless

的背景

我正在使用Scala中的事件库.在我的库中,您可以定义如下事件:

val e1 = new ImperativeEvent[Int]
Run Code Online (Sandbox Code Playgroud)

您可以像这样触发它们:

e1(42)
Run Code Online (Sandbox Code Playgroud)

你可以创建这样的反应:

val r1 = (i: Int) => println(i)
Run Code Online (Sandbox Code Playgroud)

并将它们附加到这样的事件:

e1 += r1
Run Code Online (Sandbox Code Playgroud)

还有一些其他的东西(比如事件转换,组合等).我使用Esper CEP引擎作为我的库的后端.对于大多数操作,Esper使用类似SQL的语言EPL.

问题

我正在尝试实现一些更高级的概念,如事件连接.所以现在你可以用这样的多个属性定义事件(使用元组类型):

val e2 = new ImperativeEvent[(Int, String)]
Run Code Online (Sandbox Code Playgroud)

然后像这样加入他们:

val e3 = e1 join e2 windowLength (30) on "E1.P1 = E2.P1"
Run Code Online (Sandbox Code Playgroud)

在它们各自的第一属性相等的条件下,它们在两者的最后30次出现上执行e1和e2的连接.

这没关系,但我想摆脱我的实现中的字符串,使事件表达式类型可检查.我想将连接表达式更改为以下内容:

val e3 = e1 join e2 windowLength (30) on e1._1 === e2._1
Run Code Online (Sandbox Code Playgroud)

类似于在例如中完成的方式.Squeryl.这个问题是,我无法访问元组类型元素的类型......

问题

如何静态访问元组类型?现在我只能通过反射在运行时访问它们,这对我没有帮助.我很确定我想要实现的是元组不可能实现的,但我想知道是否使用无形库中的HLists或类似的东西可能有助于实现我的目标.

Aar*_*rup 4

如果没有关于 DSL 的更多详细信息,恐怕不清楚“静态访问元组类型”的含义。这是 API 的简化版本,对于元组类型没有任何问题:

class Event[T] {
  def joinOn[T2, R](ev2: Event[T2])(f: (T, T2) => R) = new Event[R]
}
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式使用它:

val e1 = new Event[(Int, String)]
val e2 = new Event[(Int, String)]
val e3 = e1.joinOn(e2)(_._1 == _._2)
Run Code Online (Sandbox Code Playgroud)

应该很容易看出如何扩展它以支持您的 join/windowLength/on 语法。

更新: 我可以看到您的用例很复杂,因为您需要将 Scala 编码的查询表达式转换为另一种查询语言。在这种情况下,您希望on方法的签名如下所示:

def on[T2, R](f: (Expr[T], Expr[T2]) => Expr[R]): Event[R]
Run Code Online (Sandbox Code Playgroud)

在内部,每个事件对象都会创建自己的 Expr 表示形式,并将该表示形式传递到提供给该on方法的函数中。

类型Expr可以定义如下:

trait Expr[T] {
  protected val repr: String

  def _1[A](implicit ev: T <:< Tuple2[A,_]): Expr[A] = 
    ??? // create an Expr[A] whose string representation is (repr + ".P1")

  // abstracting over tuple arities (using Shapeless)
  import shapeless._, nat._
  @scala.annotation.implicitNotFound("A tuple with at least 3 elements is required")
  type At2 = ops.tuple.At[T, _2]

  def _3(implicit at: At2): Expr[at.Out] = 
    ??? // create an Expr[at.Out] whose string representation is (repr + ".P3")

  def ===(other: Expr[T]): Expr[Boolean] =
    ??? // create an Expr[T] whose string representation is (repr + " = " + other.repr)
}
Run Code Online (Sandbox Code Playgroud)

这显然大大简化了,但应该有助于您入门。