我正在尝试构建一个小型DSL,允许一些if-then-else分支具有两种类型的组合,一种是泛型(If
),另一种是具有附加功能(IfGE
)。我的印象是,混合使用低优先级的隐式特征,我可以让Scala为Else
操作选择更精确的返回类型,但它失败了。这是结构:
修改:这是一个小例子。下面是对上下文的更全面的介绍。对于回答这个问题,可能只关注这个极小的情况就足够了,而要理解我做的更长的例子可能会更好。
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)
}
但是最后两个测试(res2
和res3
)不起作用。返回类型显然不是IfGE
,而只是If[GE]
。 如何解决此问题,以便最后两个示例找到GERes
而不是AnyRes
?
答案 0 :(得分:3)
关于你的简短例子:
定义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] = ???
}