2012-06-04 57 views
4

我想了解活動模式,所以我用FizzBu​​zz玩弄:FizzBu​​zz與活動模式

let (|Fizz|_|) i = if i % 3 = 0 then Some Fizz else None 
let (|Buzz|_|) i = if i % 5 = 0 then Some Buzz else None 
let (|FizzBuzz|_|) i = if i % 5 = 0 && i % 3 = 0 then Some FizzBuzz else None 

let findMatch = function 
    | Some Fizz -> "Fizz" 
    | Some Buzz -> "Buzz" 
    | Some FizzBuzz -> "FizzBuzz" 
    | _ -> "" 

let fizzBuzz = seq {for i in 0 .. 100 -> Some i} 
       |> Seq.map (fun i -> i, findMatch i) 

這是基本正確的方法,或者是有在這裏使用活動模式更好的方法?我應該不能讓findMatch採取int而不是int選項?

回答

8

findMatch功能應該是:

let findMatch = function 
    | FizzBuzz -> "FizzBuzz" (* should be first, as pad pointed out *) 
    | Fizz -> "Fizz" 
    | Buzz -> "Buzz" 
    | _ -> "" 

您可以重寫了最後幾行:

let fizzBuzz = Seq.init 100 (fun i -> i, findMatch i) 

你的活動模式的罰款。一個替代方案是使用一個完整的有源圖案:

let (|Fizz|Buzz|FizzBuzz|Num|) i = 
    match i % 3, i % 5 with 
    | 0, 0 -> FizzBuzz 
    | 0, _ -> Fizz 
    | _, 0 -> Buzz 
    | _ -> Num i 
+0

+1爲完整的活動模式(打我吧) –

3

拆下(不必要)Some使得findMatch函數採用int作爲其參數:

let findMatch = function 
    | FizzBuzz -> "FizzBuzz" (* Should be the first pattern *) 
    | Fizz -> "Fizz" 
    | Buzz -> "Buzz" 
    | _ -> "" 

let fizzBuzz = seq { for i in 0..100 -> i, findMatch i } 
+0

不,它需要'int選項'由於匹配'Some Fizz'等。 – Daniel

+0

@Daniel:固定,仍處於編輯模式:) – pad

+2

把FizzBu​​zz案例第一。 –

10

丹尼爾的第一溶液可被簡化,因爲你不實際上需要爲FizzBuzz定義單獨的活動模式。的情況下可以被描述爲既FizzBuzz匹配,其可在所述圖案語言來表達很好:

let findMatch = function 
    | Fizz & Buzz -> "FizzBuzz" 
    | Fizz -> "Fizz" 
    | Buzz -> "Buzz" 
    | _ -> "" 

let fizzBuzz = [ for i in 0 .. 100 -> findMatch i ] 

圖案Fizz & Buzz比賽如果兩個FizzBuzz匹配。這依賴於模式先匹配的事實,所以在這種情況下訂單是相關的。我也縮短了最後一行的範圍,使我喜歡的風格稍短(但意見各不相同)。

另外,如果你不想定義了太多的單一目的的活動模式,你也可以寫一個測試的輸入是否整除任何指定編號的參數主動模式:

let (|DivisibleBy|_|) by n = if n%by=0 then Some DivisibleBy else None 

let findMatch = function 
    | DivisibleBy 3 & DivisibleBy 5 -> "FizzBuzz" 
    | DivisibleBy 3 -> "Fizz" 
    | DivisibleBy 5 -> "Buzz" 
    | _ -> "" 
+0

+1:我忘了或者從來不知道'&'是模式語言的一部分! –

+0

@Tomas:爲了準確,這是OP的解決方案,已更正。 – Daniel