FizzBuzz cu modele active

Încerc să înțeleg modele active, așa că joc cu 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)

Este aceasta abordare corectă sau există o modalitate mai bună de a utiliza modele active aici? Nu ar trebui să pot face findMatch să ia o opțiune int în loc de int?

0

3 răspunsuri

Funcția findMatch trebuie să fie:

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

Puteți rescrie ultimele rânduri:

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

Modelele tale active sunt bune. O alternativă este utilizarea unui model activ complet:

let (|Fizz|Buzz|FizzBuzz|Num|) i = 
    match i % 3, i % 5 with
    | 0, 0 -> FizzBuzz
    | 0, _ -> Fizz
    | _, 0 -> Buzz
    | _ -> Num i
0
adăugat
+1 pentru un model activ activ (mă bateți la el)
adăugat autor Stephen Swensen, sursa

Eliminați (inutil) Unele astfel încât funcția findMatch să ia ca parametru 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
adăugat
Nu, este nevoie de int option datorita potrivirii pe Some Fizz , etc.
adăugat autor Daniel, sursa
@Daniel: fix, încă în modul de editare :)
adăugat autor pad, sursa
O prindere bună pentru a pune mai întâi cazul FizzBuzz.
adăugat autor Onorio Catenacci, sursa

Prima soluție a lui Daniel poate fi simplificată, deoarece nu trebuie să definiți un model activ separat pentru FizzBuzz . Cazul poate fi descris ca potrivire Fizz și Buzz , care poate fi bine exprimată în limba de model:

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

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

The pattern Fizz & Buzz matches if both Fizz and Buzz match. This relies on the fact that the pattern is matched first, so the order is relevant in this case. I also shortened your last line a little to a style that I prefer and is a bit shorter (but opinions vary).

Alternativ, dacă nu doriți să definiți prea multe modele active cu un singur scop, puteți scrie și un model parametric activ care testează dacă o intrare este divizibilă pentru orice număr specificat:

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
adăugat
@Tomas: Pentru a fi corect, aceasta este soluția OP, corectată.
adăugat autor Daniel, sursa
+1: Am uitat sau nu știam niciodată că & face parte din limbajul de model!
adăugat autor Stephen Swensen, sursa