Reputation: 1093
I am trying to write a function that finds whether or not a given number n
is a perfect square. Here's my attempt:
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
Now, when I try to run this with sml myfile.sml
, I get the following error:
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
This doesn't seem to be a redundant pattern to me, because it only matches two constants and then anything else. Why does the compiler see this as redundant?
Upvotes: 0
Views: 694
Reputation: 51998
sqr
is not a constant, even given your let-binding of it. Syntactically, it is a variable and in the language of patterns all variables are free variables which match anything. Thus your pattern (sqr,_)
matches all arguments. The value before the comma will be bound to sqr
in the body of that clause (the RHS of the =>
), thus hiding your binding of it to z*z, and the value after it will be discarded. This covers all possible cases, hence the rest of your matches are redundant.
You can verify that variable matching in a pattern introduces a new local scope by considering the following (absolutely awful) code:
fun f xs =
let val x = 5 in
case xs of
[] => 0
| x::xs => x
end;
It compiles, but then, e.g f [1,7,10]
returns 1 instead of 5.
For your code, you need to use if ... then ... else
rather than pattern matching to handle the case of x = sqr
. Something like
(_,0) => false
| (_,_) => if x = sqr ...
(This is assuming that you still want to use pattern matching, but since you can't use it the way that you wanted to a more radical restructuring of the code that e.g. dispenses with the let
might be appropriate).
Upvotes: 1