在 SML 中,为什么不允许在模式中使用实常量?
In SML why aren't you allowed real constant in pattern?
此代码不被接受;
> fun fact 0.0 = 1.0
Error-Real constants not allowed in patterns
> | fact n = n*fact(n-1);
Static Errors
这是为什么?
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
是一个int(即使这只是由于舍入误差)。这正是 SML 的创建者试图避免的那种问题。定义 fact
和 return ints:
更有意义
fun fact x = if x = 0 then 1 else x * fact(x-1)
(或者——如果你真的想要一个浮点阶乘,请阅读 gamma 函数)。
最后一个定义可以很容易地转换成您似乎正在尝试的模式匹配形式。
此代码不被接受;
> fun fact 0.0 = 1.0
Error-Real constants not allowed in patterns
> | fact n = n*fact(n-1);
Static Errors
这是为什么?
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
是一个int(即使这只是由于舍入误差)。这正是 SML 的创建者试图避免的那种问题。定义 fact
和 return ints:
fun fact x = if x = 0 then 1 else x * fact(x-1)
(或者——如果你真的想要一个浮点阶乘,请阅读 gamma 函数)。
最后一个定义可以很容易地转换成您似乎正在尝试的模式匹配形式。