我正在写一个二进制搜索实现.我遇到的问题是模式匹配块.
使用模式匹配的代码返回奇怪的结果.第一个匹配块不会返回我期望的内容.它警告我(_,_)永远不会到达.
let binSearch (item:double) (arr:list<double>) =
let rec binSearchRec first last =
if first > last then
let lastIndex = arr.Length-1
let len = arr.Length
match (first, last) with
| (0, -1) -> System.String.Format("ITEM SMALLER THAN {0}", arr.[0])
| (len, lastIndex) -> System.String.Format("ITEM BIGGER THAN {0}", arr.[lastIndex])
| (_,_) -> System.String.Format("IN BETWEEN {0} AND {1}", arr.[last], arr.[first])
else
let mid = (first+last)/2
match item.CompareTo(arr.[mid]) with
| -1 -> binSearchRec first (mid-1)
| 0 -> "CONTAINS"
| 1 -> binSearchRec (mid+1) last
binSearchRec 0 (arr.Length-1)
Run Code Online (Sandbox Code Playgroud)
match (first, last)用这个if-else替换替换第一个调用很有效:
if first = 0 && last = -1 then
System.String.Format("ITEM SMALLER THAN {0}", arr.[0])
else if first = len && last = lastIndex then
System.String.Format("ITEM BIGGER THAN {0}", arr.[lastIndex])
else
System.String.Format("IN BETWEEN {0} AND {1}", arr.[last], arr.[first])
Run Code Online (Sandbox Code Playgroud)
我不明白该匹配调用与if-else调用的不同之处以及为什么这种方法运行良好但模式匹配块没有.
一个奇怪的结果是(len, lastIndex)匹配中的打印len在匹配内返回错误的数字.对于长度为3的数组,len匹配语句之前的打印将显示3,而匹配内的打印将显示1.
您在匹配表达式中的一个分支是创建对现有符号的新绑定
| (len, lastIndex) -> ...
Run Code Online (Sandbox Code Playgroud)
所以这个分支与其他案例相匹配.
如果要匹配匹配表达式中的现有值,则可以使用when clase:
| (a, b) when a = len && b = lastIndex -> ...
Run Code Online (Sandbox Code Playgroud)
另一种选择是将len和lastIndex声明为文字,以便在模式匹配中使用它们,但在您的情况下似乎并不自然.
[<Literal>]
let len = arr.Length
Run Code Online (Sandbox Code Playgroud)