在SML中,你为什么不允许模式中的实常数?

时间:2016-12-08 16:18:44

标签: constants sml polyml

不接受此代码;

> fun fact 0.0 = 1.0
Error-Real constants not allowed in patterns
> | fact n = n*fact(n-1);
Static Errors

为什么会这样?

1 个答案:

答案 0 :(得分:5)

real不是相等类型。 SML非常重视生成可证明正确的代码。比较两个实数是否相等往往是一个坏主意,因为x = y 可能是数学,但由于舍入错误,x != y在运行-时间。这是数字算法天真实现中臭虫的臭名昭着的来源。因为它经常是一个坏主意,SML只是禁止它。由于无法将相等的输入与模式1.0进行比较,因此将其作为模式进行比较是没有意义的。

在相对较少的情况下,您确实想要比较两个实数是否相等,您可以使用x <= y andalso x => y。或者(正如@AndreasRossberg指出的那样),可以使用标准库函数Real.==,它使用Real.==(x,y)。这最后看起来有点奇怪,所以你可以将它声明为一个中缀运算符:

val ==  = Real.==
infix 4 ==

然后简单地x == y遗憾的是,这些都不能变成一种模式,尽管它们确实可以写出来:

fun fact x = if x == 0.0 then 1.0 else x * fact(x-1.0) 

可能有意。另一方面,正如@SimonShine所指出的那样,如果你输入不是n.0形式的n,那么这将会崩溃。如果这只是由于四舍五入的错误)​​。这正是SML的创建者试图阻止的那种问题。定义fact以获取和返回整数更有意义:

fun fact x = if x = 0 then 1 else x * fact(x-1)

(或 - 如果你真的想要一个浮点因子,请阅读伽玛函数。)

最后一个定义可以很容易地转换为您似乎正在尝试的模式匹配形式。