2016-08-19 2 views
4

Я пытаюсь создать небольшую 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?

+0

сторона комментарий - написав DSL на предыдущей работы над проектом, я настоятельно рекомендую [DSLs в действии] Debasish Гош (в https://www.manning.com/книги/DSL, в действии).Он охватывает DSL на нескольких языках и посвящает несколько разделов Scala (используя библиотеку implicits + parser combinator). –

ответ

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 быть контравариантными в качестве первого параметра типа. Это заставит implicits работать на подтипы, а также:

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

Отлично, спасибо. Я думал, что это должна быть аннотация, но, вероятно, я играл с ними в другом состоянии кода. Работает как для короткого, так и для большого корпуса. –

Смежные вопросы