Scala高级类型用法
的背景
我正在Scala的一个事件库中工作。 在我的图书馆中,您可以定义像这样的事件:
val e1 = new ImperativeEvent[Int]
你可以像这样触发它们:
e1(42)
你可以创建这样的反应:
val r1 = (i: Int) => println(i)
并将它们附加到这样的事件:
e1 += r1
还有一些其他的东西(比如事件转换,组合等)。 我使用Esper CEP引擎作为我的库的后端。 对于大多数操作,Esper使用称为EPL的类似SQL的语言。
问题
我试图实现一些更高级的概念,如事件连接。 所以现在你可以用多个属性来定义事件(使用元组类型):
val e2 = new ImperativeEvent[(Int, String)]
然后像这样加入他们:
val e3 = e1 join e2 windowLength (30) on "E1.P1 = E2.P1"
在它们各自的第一个属性相等的条件下,它们在e1和e2的最后30个发生处进行联合。
这是好的,但我想摆脱我的实现中的字符串,使事件表达式类型可检查。 我想将连接表达式更改为如下所示:
val e3 = e1 join e2 windowLength (30) on e1._1 === e2._1
类似于它在例如。 Squeryl。 这个问题是,我无法访问元组类型的元素的类型...
问题
我如何静态访问元组类型? 现在我只能通过反射来访问它们,这对我没有帮助。 我非常确定,我想实现的元组不可能与元组一起使用,但是我想知道使用无形库中的HLists或类似的东西可能有助于实现我的目标。
没有关于你的DSL的更多细节,恐怕不清楚“静态访问元组类型”的含义。 这是一个简化版的API,它不会遇到元组类型的问题:
class Event[T] {
def joinOn[T2, R](ev2: Event[T2])(f: (T, T2) => R) = new Event[R]
}
你可以使用这个如下:
val e1 = new Event[(Int, String)]
val e2 = new Event[(Int, String)]
val e3 = e1.joinOn(e2)(_._1 == _._2)
应该很容易看出这可以扩展到支持你的join / windowLength / on语法。
更新:我可以看到你的用例很复杂,因为你需要将Scala编码的查询表达式翻译成另一种查询语言。 在这种情况下,您希望on
方法的签名看起来像:
def on[T2, R](f: (Expr[T], Expr[T2]) => Expr[R]): Event[R]
在内部,每个事件对象都会创建自己的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)
}
这显然很简单,但应该有助于开始。
I.有一个SynapseGrid功能反应式编程库。 在来源中你可以找到一些有用的提示。
库中的所有处理都是类型安全的。 你可以完全访问元组。
例如,如果我不得不在SynapseGrid中实现连接,我会定义一个以下签名的方法join
:
implicit class RichContact[T] (c:Contact[T]){ // contact == event in SynapseGrid's terminology
...
def join[T2](c2:Contact[T2]):Contact[(T, T2)] = {
// construct a contact/event that do nothing more than joining two events.
}
}
implicit class RichTupledContact[T, T2](c:Contact[(T, T2)])
def windowLength(len:Int):Contact[(T, T2)] = {
// construct the next step of processing events — window
}
}
等等。 逐渐建立事件处理大大简化了系统的构建。
II。 但是,如果您需要一次构建所有内容,则可以返回一些具有构建方法的中间对象:
implicit class RichContact[T] (c:Contact[T]){ // contact == event in SynapseGrid's terminology
...
def join[T2](c2:Contact[T2]):Contact[(T, T2)] = {
new {
def windowLength(len:Int) = ...
}
}
}
链接地址: http://www.djcxy.com/p/74109.html