2014-04-01 15 views
4

我需要檢查,如果列表與另一個開始,短名單。功能,使用時後衛很簡單:如何使用Active Pattern編寫startsWith列表函數,而不是在何時使用?

let rec startsWith l1 l2 = 
    match l1, l2 with 
    | [], _ | _, [] -> true 
    | x::xs, y::ys when x = y -> startsWith xs ys 
    | _ -> false 

let lst1 = [ 1; 2; 1 ] 
let lst2 = [ 1; 2; 1; 2; 3; ] 
let lst3 = [ 1; 3; 1; 2; 3; ] 

let c1 = startsWith lst1 lst2 // true 
let c2 = startsWith lst1 lst3 // false 

但無論我一起上的有源圖案的線嘗試:

let (|HeadsMatch|) (l1 : ('a) list) (l2 : ('a) list) = 
    if l1.Head = l2.Head then Some(l1.Tail, l2.Tail) else None 

let rec startsWith l1 l2 = 
    match l1, l2 with 
    | [], _ | _, [] -> true 
    | HeadsMatch /* need to capture the result */ -> startsWith t1 t2 
    | _ -> false 

我不能讓編譯。如何使用Active模式創建此功能的版本?如果這是不可能的,你能解釋爲什麼嗎?

P.S.任何其他不錯的方法來編寫上述功能?

編輯:我把片段從丹尼爾的回答,從真正的問題不分散。

編輯:開始在開始我的問題。我所定義的活躍模式功能

let (|HeadsMatch|_|) lst1 lst2 = 

,但它應該是

let (|HeadsMatch|_|) (lst1, lst2) = 

在這種情況下,將匹配在接受的答案。

回答

5

我猜想最好的方法可能是

let startsWith = Seq.forall2 (=) 

如果你想從頭開始寫,你需要匹配兩個名單:

let rec startsWith l1 l2 = 
    match l1, l2 with 
    | [], _ | _, [] -> true 
    | x::xs, y::ys when x = y -> startsWith xs ys 
    | _ -> false 

如果你想要把它寫具有學習目的的活動模式,使用Tarmil's definition它將是

let rec startsWith l1 l2 = 
    match l1, l2 with 
    | [], _ | _, [] -> true 
    | HeadsMatch(xs, ys) -> startsWith xs ys 
    | _ -> false 
+0

forall2因爲長度不同而拋出 –

+1

它是固定的。這應該是'Seq.forall2',它忽略了較長列表的其餘元素。 – Daniel

+0

有些人皺起眉頭,並說活動模式是一種避免它的方法。這是我的問題。 –

2

有在活動模式的定義兩個錯誤:

  1. 這是一個局部活躍模式(因爲它是可能的,它不匹配),所以語法是(|HeadsMatch|_|)

  2. 你需要採取兩個列表作爲一對,因爲要匹配lst1, lst2

使用這些代碼將編譯。但它會拋出運行時異常,因爲您使用列表.Head.Tail當你不知道他們是否有任何元素;如果其中一個列表爲空,則不會定義行爲。

下面是一個地道的實施HeadsMatch

let (|HeadsMatch|_|) (lst1, lst2) = 
    match (lst1, lst2) with 
    | (x :: xs, y :: ys) when x = y -> Some (xs, ys) 
    | _ -> None 

無保護:

let (|HeadsMatch|_|) (lst1, lst2) = 
    match (lst1, lst2) with 
    | (x :: xs, y :: ys) -> 
     if x = y then Some (xs, ys) else None 
    | _ -> None 

作爲一個側面說明,你的第一個實現了同樣的問題。下面將拋出一個運行時異常:

startsWith [1;2] [1] 

,因爲你不檢查lst2不就行了使用.Head.Tail前空。一般來說,你幾乎應該在幾乎所有的時候都避免這兩種方法

+0

根據定義,第一個列表更短,所以我的實現不會拋出。但問題是關於在沒有防範的情況下使用主動模式。 –

+1

我仍然儘可能避免未經檢查的前置條件。你如何確保你永遠不會有更長的名單?如果對呼叫者的要求發生變化呢?如果將來你會嘗試從一個沒有這種保證的函數中使用它呢?這種「我知道我總是用正確的論點來稱呼它」是一顆定時炸彈。 – Tarmil

+0

注意事項。問題依然存在。 –

相關問題