Чтобы создать DSL для моего нового проекта Scala, я написал следующий код:
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
чтобы найти соответствующие документы для моих входных документов в MyDocDB, используя стратегию запросов MyQueryStrategy (определяется как значение по умолчанию для этого типа ввода и DocDB через неявное).
К сожалению, у компиляции 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)
Есть предложения?
Edit:
Большое спасибо за ваши ответы. Я наконец-то выбрал решение парадигмы, поскольку оно позволяет ориентировать стратегии запросов на конкретные 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
Еще раз спасибо.