2012-06-04 5 views
4

Je suis en train de comprendre les modèles actifs, donc je suis jouer avec FizzBuzz:FizzBuzz avec des motifs actifs

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) 

Est-ce essentiellement la bonne approche, ou est-il une meilleure façon d'utiliser des motifs actifs ici ? Ne devrais-je pas être en mesure de faire findMatch prendre un int au lieu de l'option int?

Répondre

8

Votre fonction findMatch doit être:

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

Vous pouvez réécrire les dernières lignes:

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

Vos modèles actifs sont très bien. Une alternative consiste à utiliser un modèle actif complet:

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

+1 pour le motif actif complet (bat-moi dessus) –

3

Supprimer (inutile) Some de sorte que la fonction findMatch prend int comme paramètre:

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

Non, il faut 'int option' en raison de la correspondance sur' Some Fizz', etc. – Daniel

+0

@Daniel: fixe, toujours en mode d'édition :) – pad

+2

Bonne prise en mettant l'étui FizzBuzz premier. –

10

première solution de Daniel peut être simplifiée, parce que vous n » t réellement besoin de définir un modèle actif séparé pour FizzBuzz. Le cas peut être décrit comme à la fois correspondant Fizz et Buzz, qui peut être bien exprimé dans la langue du motif:

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

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

Le motif Fizz & Buzz matchs si les deux match Fizz et Buzz. Cela dépend du fait que le motif est d'abord apparié, donc l'ordre est pertinent dans ce cas. J'ai aussi raccourci un peu votre dernière ligne à un style que je préfère et qui est un peu plus court (mais les avis varient).

Sinon, si vous ne voulez pas définir trop de modèles actifs à usage unique, vous pouvez aussi écrire un modèle actif paramétrés qui teste si une entrée est divisible par un nombre spécifié:

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: J'ai oublié ou je n'ai jamais su que '&' faisait partie du langage de modèle! –

+0

@Tomas: Pour être précis, c'est la solution de l'OP, corrigée. – Daniel

Questions connexes