2015-10-09 66 views
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 

這似乎不是一個多餘的模式對我來說,因爲它只匹配兩個常量,然後是其他任何東西。爲什麼編譯器認爲這是多餘的?

回答

1

sqr不是一個常數,即使給你綁定它。在語法上,它是一個變量,並且在模式語言中,所有變量都是可以匹配任何內容的自由變量。因此你的模式(sqr,_)匹配所有參數。該逗號前面的值將被綁定到該子句(=>的RHS)中的sqr,從而將其與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威力分配代碼的更激進的重組方式適當)。