Scala数据类型用于数字实数范围

the*_*ude 12 scala

是否有一些惯用的scala类型将浮点值限制为由上限和下限定义的给定浮点范围?

具体我希望有一个浮点类型,只允许值介于0.0和1.0之间.

更具体的是我要写一个函数,它接受一个I​​nt和另一个函数,在伪scala中将这个Int映射到介于0.0和1.0之间的范围:

def foo(x : Int, f : (Int => {0.0,...,1.0})) {
    // ....
}
Run Code Online (Sandbox Code Playgroud)

已经搜查过电路板,但没有找到合适的.一些隐式魔法或自定义typedef也适合我.

Mal*_*off 8

我不知道如何静态地执行它,除了依赖类型(示例),Scala没有.如果你只处理常量,应该可以使用宏或执行必要检查的编译器插件,但如果你有任意浮点型表达式,你很可能必须求助于运行时检查.

这是一种方法.定义执行运行时检查的类,以确保浮点值在所需范围内:

abstract class AbstractRangedFloat(lb: Float, ub: Float) {
  require (lb <= value && value <= ub, s"Requires $lb <= $value <= $ub to hold")

  def value: Float
}
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式使用它:

case class NormalisedFloat(val value: Float)
  extends AbstractRangedFloat(0.0f, 1.0f)

NormalisedFloat(0.99f)
NormalisedFloat(-0.1f) // Exception
Run Code Online (Sandbox Code Playgroud)

或者:

case class RangedFloat(val lb: Float, val ub: Float)(val value: Float)
  extends AbstractRangedFloat(lb, ub)

val RF = RangedFloat(-0.1f, 0.1f) _
RF(0.0f)
RF(0.2f) // Exception
Run Code Online (Sandbox Code Playgroud)

如果可以使用值类来获得一些性能会很好,但是requires在构造函数(当前)中的调用禁止这样做.


编辑:解决@paradigmatic的评论

这是一个直观的论证,为什么依赖于自然数的类型可以在不完全支持依赖类型的类型系统中编码,但是范围浮点数可能不能:自然数是一个可枚举集,这使得对每个元素进行编码成为可能作为路径依赖类型使用Peano数字.然而,实数不再是可枚举的,因此不再可能系统地创建对应于实数的每个元素的类型.

现在,计算机浮点数和实数最终都是有限集,但仍然可以在类型系统中合理有效地枚举.设置计算机自然数当然也非常大,因此造成了在算术编码类型皮亚诺数字问题,请参阅最后一段文章.但是,我声称通常使用前n个(对于一个相当小的n)自然数就足够了,例如,由HLists证明.对浮点数做出相应的声明是不太令人信服的 - 编辑10,000浮点数在0.0和1.0之间,或者更确切地说10,000在0.0和100.0之间编码会更好吗?

  • 值得注意的是,即使Scala确实有可以表达这种情况的依赖类型,它也会付出巨大的代价.想要限制类型的人通常不会想到产生这些类型的值的额外负担.有人给你一个输入浮点数?确保您的测试程序要么在您的范围内产生浮动,要么告诉您它不适合.对一组浮点数进行复杂的数学计算,结果可以显示为适合?您需要编写一个长证明(在语言中),结果将始终适合该范围.我个人喜欢这样做,但很难...... (3认同)
  • @paradigmatic我肯定同意Scala支持*path*依赖类型,但我不相信这些允许你编码一般依赖类型允许你表达的所有东西.例如,远程浮动.而且我并不是唯一有疑虑的人,请参阅sclv对您引用的答案的评论. (2认同)