在 Scala 中使用 GADT 进行详尽检查的简洁方法?

问题描述 投票:0回答:1

我正在寻找与以下 OCaml 代码相同的行为,其中编译器理解匹配是详尽无遗的,因为我们已经表示两个审查者必须具有相同的类型:

type circle
type rectangle

type _ figure =
    | Circle : int -> circle figure
    | Rectangle : int * int -> rectangle figure

let equal_figure : type a. a figure -> a figure -> bool = fun f1 f2 -> match (f1, f2) with
| Circle r1, Circle r2 -> Int.(r1 = r2)
| Rectangle (x1, y1), Rectangle (x2, y2) -> Int.(x1 = x2 && y1 = y2)
(* the compiler knows this match is exhaustive *)

我可以将示例直接移植到 Scala,并且详尽检查器做正确的事:

sealed trait CircleMarker
sealed trait RectangleMarker

enum Fig[T]:
  case Circle(r: Int) extends Fig[CircleMarker]
  case Rectangle(x: Int, y: Int) extends Fig[RectangleMarker]

def equalFig[T](f1: Fig[T], f2: Fig[T]): Boolean = (f1, f2) match
  case (Fig.Circle(r1), Fig.Circle(r2))               => r1 == r2
  case (Fig.Rectangle(x1, y1), Fig.Rectangle(x2, y2)) => x1 == x2 && y1 == y2
  (* the compiler knows this match is exhaustive *)

斯卡斯蒂

在 Scala 中有没有更简洁的方式来表达这个,没有幻影

CircleMarker
RectangleMarker
特征?

scala enums pattern-matching gadt
1个回答
0
投票

你可以试试F-bounds

enum Fig[T <: Fig[T]]:
  case Circle(r: Int) extends Fig[Circle]
  case Rectangle(x: Int, y: Int) extends Fig[Rectangle]

// sealed trait Fig[T <: Fig[T]]
// object Fig:
//   case class Circle(r: Int) extends Fig[Circle]
//   case class Rectangle(x: Int, y: Int) extends Fig[Rectangle]

def equalFig[T <: Fig[T]](f1: Fig[T], f2: Fig[T]): Boolean = (f1, f2) match
  case (Fig.Circle(r1), Fig.Circle(r2))               => r1 == r2
  case (Fig.Rectangle(x1, y1), Fig.Rectangle(x2, y2)) => x1 == x2 && y1 == y2

// def equalFig[T <: Fig[T]](f1: Fig[T], f2: Fig[T]): Boolean = f1 == f2

equalFig(Fig.Circle(1), Fig.Circle(1)) // true
equalFig(Fig.Circle(1), Fig.Circle(2)) // false
equalFig(Fig.Rectangle(1, 2), Fig.Rectangle(1, 2)) // true
equalFig(Fig.Rectangle(1, 2), Fig.Rectangle(1, 3)) // false
// equalFig(Fig.Circle(1), Fig.Rectangle(1, 2)) // doesn't compile
© www.soinside.com 2019 - 2024. All rights reserved.