If-Then-Else DSL - 定义隐式来区分两种 return 类型

If-Then-Else DSL - define implicits to distinguish two return types

我正在尝试构建一个小型 DSL,它允许一些具有两种组合类型的 if-then-else 分支,一种是通用的 (If),另一种是具有附加功能的 (IfGE)。我的印象是,通过混合低优先级的隐式特征,我可以使 Scala select 成为 Else 操作的更精确的 return 类型,但它失败了。这是构造:

编辑:这是一个最小的例子。下面是对上下文的更彻底的演练。为了回答这个问题,可能只关注这个最小的案例就足够了,而为了理解我在做什么,更长的例子可能会更好。


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) 具有一些隐式的图形元素,使用数字作为图形元素并应用二元运算符:

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)
}

但是最后两个测试(res2res3)不起作用。 return 类型显然不是 IfGE 而只是 If[GE]我该如何解决这个问题,以便最后两个示例找到 GERes 而不是 AnyRes

关于您的较短示例:

定义 implicit def GERes: Result[GE, IfGE] 完全对应于类型 GE,但是 WhiteNoise() 具有类型 WhiteNoise <: GE,这不符合隐式。


您可以更改隐式的定义以适用于 GE:

的子类型
object Result extends LowPri {
  implicit def GERes[T <: GE]: Result[T, IfGE] = ???
}

或者在其第一个类型参数中定义Result是逆变的。这将使隐式也适用于子类型:

sealed trait Result[-A, Out]
object Result extends LowPri {
  implicit def GERes: Result[GE, IfGE] = ???
}