我正在尝试编写一个函数来查找给定数字n
是否是一个完美的正方形。这是我的尝试:
local
fun perfect_square_iter x z = let val sqr = z * z in
case (x,z) of
(sqr,_) => true
| (_, 0) => false
| _ => perfect_square_iter x (z - 1)
end
in fun perfect_square n = perfect_square_iter n n
end
现在,当我尝试使用sml myfile.sml
运行时,我收到以下错误:
lab03.sml:17.5-20.43 Error: match redundant
(sqr,_) => ...
--> (_,0) => ...
--> _ => ...
/usr/lib/smlnj/bin/sml: Fatal error -- Uncaught exception Error with 0
raised at ../compiler/FLINT/trans/translate.sml:1735.13-1735.21
这对我来说似乎不是一个多余的模式,因为它只匹配两个常量,然后是其他任何东西。为什么编译器认为这是多余的?
答案 0 :(得分:1)
sqr
不是一个常量,即使你让它绑定它。从语法上讲,它是一个变量,在模式语言中,所有变量都是与任何东西匹配的自由变量。因此,您的模式(sqr,_)
匹配所有参数。逗号之前的值将绑定到该子句正文中的sqr
(=>
的RHS),从而隐藏它与z * z的绑定,后面的值将是丢弃。这涵盖了所有可能的情况,因此其余的匹配都是多余的。
您可以通过考虑以下(绝对可怕的)代码来验证模式中的变量匹配是否引入了新的本地范围:
fun f xs =
let val x = 5 in
case xs of
[] => 0
| x::xs => x
end;
它编译,但是,例如f [1,7,10]
返回1而不是5.
对于您的代码,您需要使用if ... then ... else
而不是模式匹配来处理x = sqr
的情况。像
(_,0) => false
| (_,_) => if x = sqr ...
(这假设您仍然希望使用模式匹配,但是因为您不能以您希望对代码进行更彻底的重组的方式使用它,例如免除let
可能是合适的)。