Langston
Langston

Reputation: 1093

Redundant Pattern Matching

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

Answers (1)

John Coleman
John Coleman

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

Related Questions