0

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

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

4

1 回答 1

1

sqr不是一个常数,即使考虑到你的 let-binding 。从语法上讲,它是一个变量,在模式语言中,所有变量都是匹配任何东西的自由变量。因此,您的模式(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可能是合适的)。

于 2015-10-09T20:20:16.010 回答