Reputation: 397
I'm writing a binary search implementation. The problem I have is with a pattern matching block.
This code using pattern matching returns weird results. The first match block does not return what I expect. It warns me that (_,_)
is never reached.
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)
Replacing that first match (first, last)
call with this if-else alternative works well:
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])
I don't understand how that match call is different from this if-else call and why this works well but the pattern matching block does not.
A weird result is that printing len in the (len, lastIndex)
match returns wrong numbers inside the match. For an array of length three a print of len
before the match statement will show 3 whereas a print inside the match will show 1.
Upvotes: 3
Views: 404
Reputation: 2395
One of your branch in match expression is creating new bindings to existing symbols
| (len, lastIndex) -> ...
so this branch matches with every other case.
If you what to match against existing values in match expression you can use when clase for that:
| (a, b) when a = len && b = lastIndex -> ...
Another option would be declaring len and lastIndex as literals to use them in pattern matching but it seems not natural in your case.
[<Literal>]
let len = arr.Length
Upvotes: 8