2015-10-06 2 views
3

Я пишу реализацию бинарного поиска. У меня проблема с блоком соответствия шаблонов.F # Weird pattern matching result

Этот код с использованием сопоставления образцов возвращает странные результаты. Первый блок соответствия не возвращает то, что я ожидаю. Он предупреждает меня, что (_,_) так и не был достигнут.

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) 

Замена, что первый match (first, last) вызов с этим, если-то еще альтернативы работает хорошо:

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]) 

Я не понимаю, как этот вызов матч отличается от этого, если-то еще звонок, и почему это хорошо работает но блок сопоставления шаблонов не работает.

Странным результатом является то, что печать len в матче (len, lastIndex) возвращает неправильные номера внутри матча. Для массива длины три оттиск len перед оператором матча покажет 3, тогда как печать внутри матча покажет 1.

ответ

8

Одна из вашей отрасли в выражении соответствия создает новые привязки к существующим символам

| (len, lastIndex) -> ... 

так что эта ветка соответствует каждому другому случаю.

Если вы что в соответствии с существующими значениями в выражении соответствия можно использовать при Clase для этого:

| (a, b) when a = len && b = lastIndex -> ... 

Другим вариантом было бы объявить Len и LastIndex, как литералы, чтобы использовать их в сопоставлении с образцом но в вашем случае это кажется неестественным.

[<Literal>] 
let len = arr.Length 
+3

Literal не может использоваться в этом случае в любом случае, вы можете использовать его только для, ну, буквальных значений, а не для значений времени исполнения, таких как 'arr.Length'. – Tarmil