我正在用 Scala 编写一个库,并决定使用 3.5.0 版本中引入的更新(实验)语法来处理类型类。所以我的代码有:
trait HasBoundary:
type Self
extension (self : Self)
def boundary[Coefficient : Fractional] : Chain[Self, Coefficient]
trait HasDimension:
type Self
extension (self : Self)
def dim : Int
trait OrderedCell extends HasBoundary with HasDimension
class Chain[Cell : OrderedCell, Coefficient : Fractional](val entries : Map[Cell, Coefficient])
sealed trait ElementaryInterval:
def n : Int
case class DegenerateInterval(n : Int) extends ElementaryInterval
case class FullInterval(n : Int) extends ElementaryInterval
此时,我发现自己正在努力编写
given
语句以使整个 GADT ElementaryInterval = DegenerateInterval | FullInterval
成为 OrderedCell
类型类的成员。
我可以写:
given DegenerateInterval is OrderedCell:
extension (t : DegenerateInterval)
def boundary[CoefficientT : Fractional] = Chain(Map.empty)
def dim : Int = 0
end extension
end given
given FullInterval is OrderedCell:
extension (t : DegenerateInterval)
def boundary[CoefficientT : Fractional as fr] = Chain(Map.from(DegenerateInterval(t.n+1) → fr.one, DegenerateInterval(t.n) → fr.negate(fr.one)))
def dim : Int = 1
end extension
end given
但是我的
boundary
函数没有给出正确的返回类型 - 它们似乎需要坚持各自的案例类,并且无法爬上继承层次结构。
或者我可以将其全部写为
ElementaryInterval
类型,如
given ElementaryInterval is OrderedCell:
extension (t : ElementaryInterval)
def boundary[Coefficient : Fractional as fr] = t match {
case DegenerateInterval(_) => Chain(Map.empty)
case FullInterval(n) => Chain(Map.from(DegenerateInterval(n+1) → fr.one, DegenerateInterval(n) → fr.negate(fr.one)))
end extension
end given
但是,在构建包含
Chain
或 DegenerateInterval
的 FullInterval
对象时,我似乎遇到了问题,因为它会为案例类寻找 given
子句,而不是我为密封编写的子句。特质。
所以,总结一下我的问题/问题:
我可以将类型类的新语法与 GADT 的
sealed trait
/ case class
模式结合起来吗?如何编写 given
子句来实现类型类成员资格,以便它与 GADT 中的继承结构兼容?
是否有某种方法可以以某种合理的方式注释
given
实例中的方差?
我仍然想更好地理解 GADT 构造和类型类之间的相互作用,但我已经成功解决了这个特殊的结:
关键似乎是比预期更多的地方显式类型注释。以下似乎有效:
given ElementaryInterval is OrderedCell:
extension (t : ElementaryInterval)
def boundary[Coefficient : Fractional as fr] = t match {
case DegenerateInterval(_) => Chain[ElementaryInterval, Coefficient](Map.empty)
case FullInterval(n) => Chain[ElementaryInterval, Coefficient](Map.from(DegenerateInterval(n+1) → fr.one, DegenerateInterval(n) → fr.negate(fr.one)))
def dim : Int = t match {
case DegenerateInterval(_) => 0
case FullInterval(_) => 1
}
换句话说,如果我不允许类型推断落在
Chain[DegenerateInterval, Coefficient]
之类的东西上,它会在检查Chain
上的条件时正确解析给定的实例。