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)
不幸的是,这不是您可以在编译时轻松检查的内容。好吧 - 至少如果你不限制你的类型的操作的话就不会。如果您的目标只是检查数字文字是否非零,您可以轻松编写一个宏来检查此属性。然而,我认为证明负数确实是负数没有任何好处。
问题不是 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,因为你不知道它是正数还是负数。因此,为了静态安全,您必须采取保守的方法并禁止此类操作。
有更复杂的数值域,但最终,它们都遇到相同的问题:它们代表了对实际程序状态的过度近似。
我想说这个问题类似于整数上溢/下溢:通常,您静态地不知道操作是否表现出溢出 - 您只能在运行时知道这一点。