冗余模式匹配

时间:2015-10-09 18:48:31

标签: pattern-matching sml ml perfect-square

我正在尝试编写一个函数来查找给定数字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

这对我来说似乎不是一个多余的模式,因为它只匹配两个常量,然后是其他任何东西。为什么编译器认为这是多余的?

1 个答案:

答案 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可能是合适的)。