Я пытаюсь создать небольшую DSL, которая позволяет использовать ветви if-then-else с двумя типами композиций, один общий (If
) и один с добавленными возможностями (IfGE
). У меня создалось впечатление, что при микшировании в неявной черте с низким приоритетом я могу сделать Scala более точным возвращаемым типом для операции Else
, но он терпит неудачу. Вот конструкция:If-Then-Else DSL - определить implicits для различения двух типов возврата
Редактировать: Вот минимальный случай. Далее ниже - более тщательный анализ контекста. Для ответа на вопрос, вероятно, сосредоточиться на этом минимальном случае достаточно, хотя понять, что я делаю, более длинный пример может быть лучше.
trait GE
trait If[A] {
def Else[B >: A, Out](cond: => B)(implicit result: Result[B, Out]): Out
}
trait IfGE extends If[GE] with GE
case class SinOsc() extends GE
case class WhiteNoise() extends GE
trait LowPri {
implicit def AnyRes[A]: Result[A, If[A]] = ??? // !
}
object Result extends LowPri {
implicit def GERes: Result[GE, IfGE] = ???
}
sealed trait Result[A, Out]
def IfExample: If[SinOsc]
val res1: GE = IfExample.Else(WhiteNoise())
val res2: GE = IfExample.Else[GE, IfGE](WhiteNoise())
Здесь вывод типа и неявная резолюция не для res1
, в то время как явно положить типы в res2
делают его работу. Мне нужно получить res1
, т. Е. Без указания параметров типа.
дольше пример:
(1) Граф элемент с некоторым implicits использовать число в качестве элементов графа и применить бинарные операторы:
object GE {
implicit def intIsGE (x: Int ): GE = ???
implicit def doubleIsGE(x: Double): GE = ???
implicit class GEOps(private val ge: GE) extends AnyVal {
def <= (that: GE): GE = ???
def > (that: GE): GE = ???
def & (that: GE): GE = ???
def poll(): Unit = ???
}
}
trait GE
(2) Ветвящаяся структура:
object If {
def apply(cond: => GE): IfBuilder = ???
}
trait IfBuilder {
def Then [A](branch: => A): If[A]
}
trait If[A] {
def Else: ElseBuilder[A]
def ElseIf(cond: => GE): ElseIfBuilder[A]
}
trait IfGE extends If[GE] with GE
object ElseBuilder {
trait LowPri {
implicit def AnyRes[A]: Result[A, If[A]] = ???
}
object Result extends LowPri {
implicit def GERes: Result[GE, IfGE] = ???
}
sealed trait Result[A, Out]
}
trait ElseBuilder[A] {
def apply[B >: A, Out](b: => B)(implicit res: ElseBuilder.Result[B, Out]): Out
}
trait ElseIfBuilder[A] {
def Then [B >: A](branch: => B): If[B]
}
(3) Некоторые примеры элементов графа:
case class Out(signal: GE)
case class SinOsc(freq: GE) extends GE
case class Dust(freq: GE) extends GE
case class WhiteNoise() extends GE
(4) Тестовый набор:
trait Tests {
def freq: GE
// ---- Unit/Any result ----
val res0 = If (freq > 600) Then {
Out(SinOsc(freq))
}
val res1 = If (freq > 400 & freq <= 600) Then {
Out(SinOsc(freq))
} Else {
freq.poll()
}
// ---- GE result ----
val res2: GE = If (freq > 100) Then {
SinOsc(freq)
} Else {
WhiteNoise()
}
val res3: GE = If (freq > 1000) Then {
SinOsc(freq)
} ElseIf (freq > 100) Then {
Dust(freq)
} Else {
WhiteNoise()
}
Out(res3)
}
Но последние два теста (res2
и res3
) не работают. Тип возврата не равен IfGE
, но только If[GE]
. Как это исправить, так что в последних двух примерах можно найти GERes
вместо AnyRes
?
сторона комментарий - написав DSL на предыдущей работы над проектом, я настоятельно рекомендую [DSLs в действии] Debasish Гош (в https://www.manning.com/книги/DSL, в действии).Он охватывает DSL на нескольких языках и посвящает несколько разделов Scala (используя библиотеку implicits + parser combinator). –