基于Scala约束的类型和文字

Dav*_*ank 6 types scala constraints scala-macros

我在想是否可以在Scala中定义类似的类型NegativeNumber.此类型将表示负数,编译器将检查它与Ints,Strings等类似.

val x: NegativeNumber = -34
val y: NegativeNumber = 34 // should not compile
Run Code Online (Sandbox Code Playgroud)

同样:

val s: ContainsHello = "hello world"
val s: ContainsHello = "foo bar" // this should not compile either
Run Code Online (Sandbox Code Playgroud)

我可以像其他类型一样使用这些类型,例如:

def myFunc(x: ContainsHello): Unit = println(s"$x contains hello")
Run Code Online (Sandbox Code Playgroud)

这些约束类型可以由临时类型(Int,String)支持.

是否可以实现这些类型(可能使用宏)?

自定义文字怎么样?

val neg = -34n  //neg is of type NegativeNumber because of the suffix
val pos = 34n  // compile error
Run Code Online (Sandbox Code Playgroud)

Kul*_*mpa 3

不幸的是,这不是您可以在编译时轻松检查的内容。好吧 - 至少如果你不限制你的类型的操作的话就不会。如果您的目标只是检查数字文字是否非零,您可以轻松编写一个宏来检查此属性。然而,我认为证明负数确实是负数没有任何好处。

问题不是 Scala 的限制——它有一个非常强大的类型系统——而是事实上(在一个相当复杂的程序中)你无法静态地知道每一个可能的状态。然而,您可以尝试过度近似所有可能状态的集合。

NegativeNumber让我们考虑引入仅表示负数的类型的示例。为了简单起见,我们只定义一个操作:plus。

假设您只允许添加 multiple NegativeNumber,那么类型系统可以用来保证每个NegativeNumber确实是负数。但这似乎确实具有限制性,因此一个有用的示例肯定允许我们添加至少 aNegativeNumber和 a generic Int。

如果您有一个表达式,但您不知道和 的静态val z: NegativeNumber = plus(x, y)值(也许它们是由函数返回的),该怎么办?你怎么知道(静态地)这确实是一个负数?xyz

解决该问题的一种方法是引入抽象解释,它必须在程序的表示上运行(源代码、抽象语法树……)。

例如,您可以使用以下元素在数字上定义一个格:

  • Top:所有数字
  • +:所有正数
  • 0: 号码0
  • -:所有负数
  • Bottom: 不是一个数字 - 只是介绍每对元素都有一个最大下界

顺序为Top> ( +, 0, -) > Bottom。

符号格

然后您需要为您的操作定义语义。从我们的例子中采用交换法plus:

  • plus(Bottom, something)总是如此Bottom,因为您无法使用无效数字来计算某些内容
  • plus(Top, x),x != Bottom总是Top,因为任意数与任意数相加始终是任意数
  • plus(+, +)是+,因为两个正数相加总会得到一个正数
  • plus(-, -)是-,因为两个负数相加总是会得到一个负数
  • plus(0, x),x != Bottom是x, 因为0是加法的恒等式。

问题是

  • plus - +将会是Top,因为你不知道它是正数还是负数。

因此,为了静态安全,您必须采取保守的方法并禁止此类操作。

有更复杂的数值域,但最终,它们都遇到相同的问题:它们代表了对实际程序状态的过度近似。

我想说这个问题类似于整数上溢/下溢:通常,您静态地不知道操作是否表现出溢出 - 您只能在运行时知道这一点。