【发布时间】:2011-08-13 14:13:50
【问题描述】:
为了为我的新 Scala 项目创建 DSL,我编写了以下代码:
trait DocDB[O] {
def searchFor[I] (docs: Iterable[I], queryStrategy: QueryStrategy[I, DocDB[_]]): Iterable[(I,O)]
}
trait QueryStrategy[I, +F <: DocDB[_]]
class In // class of input documents
class Out // class of output documents
// MyDocDB
object MyDocDB extends DocDB[Out] {
def searchFor[I] (docs: Iterable[I], queryStrategy: QueryStrategy[I, DocDB[_]]) = List()
}
// MyQueryStrategy for In and MyDocDB
implicit object MyQueryStrategy extends QueryStrategy[In, MyDocDB.type]
implicit def listExt[I] (items: Iterable[I]) = new {
def findAt[O, F <: DocDB[O]](docDB: F) = new {
def apply(implicit queryStrategy: QueryStrategy[I, F]): Iterable[(I,O)] = {
docDB.searchFor[I](items, queryStrategy)
}
}
}
我真正想要的是能够写作
val out1: Iterable[(In, Out)] = List[In]() findAt MyDocDB
通过使用查询策略 MyQueryStrategy(为此输入类型和 DocDB 通过隐式定义的默认值)在 MyDocDB 中查找我的输入文档的相应文档。
不幸的是,Scala 编译时该行存在问题。它声称它无法推断类型:
error: inferred type arguments [Nothing,test.StackOverflow.MyDocDB.type] do not conform to method findAt's type parameter bounds [O,F <: test.StackOverflow.DocDB[O]]
val out1: Iterable[(In, Out)] = List[In]() findAt MyDocDB
不知何故,它推断出Nothing 而不是Out。如果不明确告诉编译器它应该假定O 的类型为Out,我该如何解决这个问题?我的意思是,以下内容有效,但不会导致简洁的 DSL:
val out2: Iterable[(In, Out)] = List[In]().findAt[Out, MyDocDB.type](MyDocDB).apply(MyQueryStrategy)
有什么建议吗?
编辑:
非常感谢您的回答。我终于采用了范式的解决方案,因为它允许查询策略可以针对我在项目中实际需要的特定 DocDB。除了范例的解决方案,我将 listExt 函数替换为
implicit def listExt[I] (items: Iterable[I]) = new {
def findAt[F <: DocDB](docDB: F)(implicit queryStrategy: QueryStrategy[I, F]): Iterable[(I,F#O)] = {
docDB.searchFor[I](items, queryStrategy)
}
}
这样我就可以省略 apply 方法和隐式 QueryStrategy:
val out1: Iterable [(In,Out)] = List[In]() findAt MyDocDB
再次感谢。
【问题讨论】:
标签: scala dsl type-inference type-systems