Допустим, у меня есть два типа 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 в один GADT с именем All
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 и произвольно объединить их в одну алгебру, поэтому я ищу более общий c подход для замены DualInterpreter
выше. Я вижу, что сигнатура типа - это что-то вроде
case class ArbitraryInterpreter[ALG[_]<:Coproduct,A](???) extends Interpreter[ALG,A] {
override def description(a: ALG[A]): String = ???
}
. Главное, что я хотел бы абстрагировать, - это сопоставление с шаблоном внутри метода description
, поскольку оно может быть довольно уродливым с числом. доступных алгебр. Будет иметься интерпретатор, где аргументы конструктора являются интерпретаторами, а делегаты сопоставления с образцом соответствующему интерпретатору на основе типа ALG, переданного в метод описания.