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

Ton*_*aro 2 constants sml polyml

此代码不被接受;

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

为什么是这样?

Joh*_*man 5

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

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

val ==  = Real.==
infix 4 ==
Run Code Online (Sandbox Code Playgroud)

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

fun fact x = if x == 0.0 then 1.0 else x * fact(x-1.0) 
Run Code Online (Sandbox Code Playgroud)

这可能是有意的.在另一方面,作为@SimonShine指出,这将如果你给它的任何输入,崩溃不是形式的n.0地方n是一个int(即使这仅仅是由于舍入误差).这正是SML的创建者试图阻止的那种问题.定义fact获取和返回int 更有意义:

fun fact x = if x = 0 then 1 else x * fact(x-1)
Run Code Online (Sandbox Code Playgroud)

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

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

  • 值得注意的是,如果你明确地想要它,你也有'真实.==`. (2认同)
  • 我不确定如何`有趣的事实x =如果x == 0.0然后...`打算工作,但如果由于某种原因,输入`x`以错误的方式舍入,该函数将抛出`Out_of_memory `.浮动应该[正确比较](http://floating-point-gui.de/errors/comparison/).:-) (2认同)