【发布时间】:2021-05-16 04:46:09
【问题描述】:
我目前正在尝试编写 DSL 的 scala 类型系统。我想要的是以下内容:
// custom dsl
val out = TagA(
TagB(),
TagC(
TagC()
TagA()
),
)
-
TagA接受0..nTagB或TagC参数,但不接受TagA -
TagB不接受任何参数 -
TagC接受0..nTagC或TagA参数,但不接受TagB
所以基本上我试图在 varargs 参数中传递各种分离类型。我想我可以限制每个Tag 使用类型类接受的具体类型。因此我对TagA、TagB和TagC建模如下:
case class TagA[A: TagAChildren](children: A*)
case object TagB
case class TagC[A: TagCChildren](children: A*)
sealed trait TagAChild[-T]
object TagAChildren {
implicit object TagBWitness extends TagAChild[TagB]
implicit object TagCWitness extends TagAChild[TagC]
}
sealed trait TagCChild[-T]
object TagCChildren {
implicit object TagCWitness extends TagCChild[TagC]
implicit object TagAWitness extends TagCChild[TagA]
}
现在,如果我传递单一类型,这可以正常工作。例如:
TagA() // compiles
TagA( // compiles
TagB(),
TagB(),
)
但是,如果我混合使用例如 TagB 和 TagC,编译会失败:
TagA(
TagB(),
TagC(),
)
// could not find implicit value for evidence parameter of type TagAChild[Product with java.io.Serializable]
显然编译器找不到隐含的。我想我在这里对编译器的要求有点太多了......有人能想出一些办法来完成这项工作吗?非常感谢任何提示或替代方法。
【问题讨论】:
-
在 TagAChildren 中,使用 TagAChild 作为 TabBWitness 和 TagCWitness 的扩展。有帮助吗?
-
Doh,写下问题的类型混乱。感谢您指出。但问题仍然存在。
-
这个问题有两种解决方案。 1) 磁铁图案 - 2) 无形。在这种情况下,我个人会选择磁铁,这是最简单的解决方案,其他多个库都使用它来解决同样的问题。
-
感谢分享。不知道磁铁图案是一回事。一定会看看的。
-
@Luis 真棒,原来磁铁图案正是我想要的。如果你想整理一个最小的例子,我会接受这个作为答案。否则我将在下周自己为其他人发布答案。
标签: scala types compiler-errors typeclass