FizzBuzz с активными шаблонами
Я пытаюсь понять Active Patterns, поэтому я играю с FizzBuzz:
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?
Ответы
Ответ 1
Ваша функция 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
Ответ 2
Первое решение Daniel может быть упрощено, поскольку на самом деле вам не нужно определять отдельный активный шаблон для FizzBuzz
. Случай можно описать как совпадение Fizz
и Buzz
, которое может быть хорошо выражено в языке шаблонов:
let findMatch = function
| Fizz & Buzz -> "FizzBuzz"
| Fizz -> "Fizz"
| Buzz -> "Buzz"
| _ -> ""
let fizzBuzz = [ for i in 0 .. 100 -> findMatch i ]
Образец Fizz & Buzz
соответствует совпадению как Fizz
, так и Buzz
. Это зависит от того, что шаблон согласован первым, поэтому в этом случае порядок имеет значение. Я также немного сократил вашу последнюю строку до стиля, который я предпочитаю, и немного короче (но мнения меняются).
В качестве альтернативы, если вы не хотите определять слишком много одноцелевых активных паттернов, вы также можете написать параметризованный активный шаблон, который проверяет, делится ли вход по любому указанному числу:
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"
| _ -> ""
Ответ 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 }