假设我有两种 GADT 类型。
abstract class Numbers[A]()
case class IntType() extends Numbers[Int]
abstract class Letters[A]()
case class EnglishType() extends Letters[String]
我为每种 GADT 类型都有一个解释器,它将打印出每个 GADT 子类型的描述。
trait Interpreter[ALG[_],A] {
def description(a: ALG[A]) : String
}
case class NumbersInterpreter[A]() extends Interpreter[Numbers,A] {
override def description(a: Numbers[A]): String =
a match {
case i: IntType => "Int"
}
}
case class LettersInterpreter[A]() extends Interpreter[Letters,A] {
override def description(a: Letters[A]): String =
a match {
case e: EnglishType => "English"
}
}
我希望将两个 GADT 合并为一个名为 All 的 GADT
type All[A] = Numbers[A] :+: Letters[A] :+: CNil
我可以通过硬编码所有 GADT 值来创建一个新的解释器。
case class DualInterpreter[A](
numbersInterpreter: NumbersInterpreter[A],
lettersInterpreter: LettersInterpreter[A]) extends Interpreter[All,A] {
override def description(a: All[A]): String =
a match {
case Inl(num) => numbersInterpreter.description(num)
case Inr(Inl(let)) => lettersInterpreter.description(let)
case _ => sys.error("Unreachable Code")
}
}
但是,我想添加一堆 GADT 代数和解释器,并将它们任意组合成一个代数,所以我正在寻找一种更通用的方法来替换DualInterpreter
上述内容。我可以看到类型签名类似于
case class ArbitraryInterpreter[ALG[_]<:Coproduct,A](???) extends Interpreter[ALG,A] {
override def description(a: ALG[A]): String = ???
}
我想抽象的主要是description
方法内部的模式匹配,因为可用代数的数量可能会变得非常丑陋。它将有一个解释器,其中构造函数参数是解释器,并且模式匹配根据传递给描述方法的 ALG 类型委托给适当的解释器。