是否可以创建一个 restricted Int(例如PositiveInt)并对其进行编译时检查?换句话说,是否可以定义一个方法,例如:
def myMethod(x: PositiveInt) = x + 1
然后有这样的东西:
myMethod(-5) // does not compile
myMethod(0) // does not compile
myMethod(5) // compiles
如果这是可能的,我应该如何开始定义PositiveInt,我的意思是,在Scala中是否有一个方便的技术?
6条答案
按热度按时间ltskdhd11#
这种东西叫做dependent typing,Scala中没有。
brc7rcf02#
如果你有编译时依赖的类型检查,你解决了停机问题,或者你的编译器并不总是保证完成编译,或者你的编程语言的语法需要图灵完成,所有这些都是荒谬的事情。
下面是在 runtime 期间依赖类型化的合理替代方法
mlmc2os53#
可以按以下方式在原始类型上使用标记特征
但是,在编写
makePositive(-5)
时只会出现运行时错误,而在编写succ(5)
时会出现编译时错误。也许可以编写一个编译器插件,将正整数文字“提升”到一个标记类型。
编辑
我还没有测试过以这种方式标记基元类型是否有任何运行时开销。
jdzmm42g4#
其他的答案主要是关于创建一个“正数”类型,该类型以编译器可以保证正确性的方式与一个“数字”类型相关联。例如,使用依赖类型,你可以证明像
abs
这样的函数的实现是正确的,而使用scala则不能。不过,您可以建置只表示自然数的型别。例如:
这与ziggystar提出的方法类似,不同之处在于类型的正确性是由它自己的构造来保证的,而不是由构造函数来保证的,也就是说,用这种类型不可能表示负数。
这种方法可能不适合您的目的。您要么需要实现它的所有操作,要么需要附带Int值,这样就相当于只进行一次运行时检查,因为您失去了通过这种方式表示正整数所赢得的所有类型安全。
由于
Pos.apply
不是类型安全的,所以在ac1kyiln5#
是的。它们被称为精炼类型。请检查:https://github.com/fthomas/refined以获取更多详细信息。
不需要自己实现任何东西,没有
apply
方法等。只需使用它..:)g6baxovj6#
有几种方法可以避免
Int
为负,但它总是有一些缺点。精炼库非常强大,但据我所知,目前它与Scala 3仍然存在一些兼容性问题。不过,我对Scala 3非常满意,因为现在可以使用
inline
关键字来防止对负数进行编译,如下所示:好的IDE(如IntelliJ)和编译器都会让你知道,如果你试图做一些被禁止的事情,那就有错误。