Padrões de ativos (F#)
Padrões Active permitem que você definir partições nomeadas que subdividir os dados de entrada, para que você possa usar esses nomes em um padrão de expressão de correspondência, assim como faria em uma união discriminada.Você pode usar padrões de ativos para decompor os dados de maneira personalizada para cada partição.
// Complete active pattern definition.
let (|identifer1|identifier2|...|) [ arguments ] = expression
// Partial active pattern definition.
let (|identifier|_|) [ arguments ] = expression
Comentários
Na sintaxe anterior, os identificadores são nomes para partições de dados de entrada são representados por arguments, ou, em outras palavras, os nomes para subconjuntos do conjunto de todos os valores dos argumentos.Pode haver até sete partições em uma definição padrão ativo.O expression descreve o formulário no qual será a decompor os dados.Você pode usar uma definição padrão ativo para definir as regras para determinar qual das partições nomeadas valores fornecidos como argumentos pertencem a.O (| e |) símbolos são chamados de clipes banana e a função criada por esse tipo de associação let é chamado um reconhecedor active.
Por exemplo, considere o seguinte padrão ativo com um argumento.
let (|Even|Odd|) input = if input % 2 = 0 then Even else Odd
Você pode usar o padrão ativo em um padrão de correspondência da expressão, como no exemplo a seguir.
let TestNumber input =
match input with
| Even -> printfn "%d is even" input
| Odd -> printfn "%d is odd" input
TestNumber 7
TestNumber 11
TestNumber 32
A saída deste programa é o seguinte:
7 is odd
11 is odd
32 is even
Outro uso de padrões de ativos é decompor os tipos de dados de várias formas, como quando os mesmos dados subjacentes tem várias representações possíveis.Por exemplo, um Color objeto poderia ser decomposto em uma representação de RGB ou uma representação HSB.
open System.Drawing
let (|RGB|) (col : System.Drawing.Color) =
( col.R, col.G, col.B )
let (|HSB|) (col : System.Drawing.Color) =
( col.GetHue(), col.GetSaturation(), col.GetBrightness() )
let printRGB (col: System.Drawing.Color) =
match col with
| RGB(r, g, b) -> printfn " Red: %d Green: %d Blue: %d" r g b
let printHSB (col: System.Drawing.Color) =
match col with
| HSB(h, s, b) -> printfn " Hue: %f Saturation: %f Brightness: %f" h s b
let printAll col colorString =
printfn "%s" colorString
printRGB col
printHSB col
printAll Color.Red "Red"
printAll Color.Black "Black"
printAll Color.White "White"
printAll Color.Gray "Gray"
printAll Color.BlanchedAlmond "BlanchedAlmond"
A saída do programa acima é o seguinte:
Red
R: 255 G: 0 B: 0
H: 0.000000 S: 1.000000 B: 0.500000
Black
R: 0 G: 0 B: 0
H: 0.000000 S: 0.000000 B: 0.000000
White
R: 255 G: 255 B: 255
H: 0.000000 S: 0.000000 B: 1.000000
Gray
R: 128 G: 128 B: 128
H: 0.000000 S: 0.000000 B: 0.501961
BlanchedAlmond
R: 255 G: 235 B: 205
H: 36.000000 S: 1.000000 B: 0.901961
Juntas, essas duas maneiras de usar os padrões de ativos permitem a partição e decompõem dados em apenas o apropriado formulário em executam as computações apropriadas nos dados apropriados no formulário mais conveniente para a computação.
As expressões de correspondência de padrão resultante permitem que os dados sejam gravados em uma opção conveniente que é muito legível, simplificando bastante a ramificação potencialmente complexa e o código de análise de dados.
Padrões de Active parciais
Às vezes, você precisa de partição somente parte do espaço de entrada.Nesse maiúsculas e minúsculas, você escreve um conjunto de padrões parcial de cada um dos que correspondem a algumas entradas, mas não conseguem igualar outras entradas.Padrões ativos que produz um valor sempre são chamados de parcial padrões active; eles têm um valor retornado que é um tipo de opção.Para definir um padrão de active parcial , você pode usar um caractere curinga (_) no final da lista de padrões dentro dos clipes de banana.O código a seguir ilustra o uso de um padrão de active parcial .
let (|Integer|_|) (str: string) =
let mutable intvalue = 0
if System.Int32.TryParse(str, &intvalue) then Some(intvalue)
else None
let (|Float|_|) (str: string) =
let mutable floatvalue = 0.0
if System.Double.TryParse(str, &floatvalue) then Some(floatvalue)
else None
let parseNumeric str =
match str with
| Integer i -> printfn "%d : Integer" i
| Float f -> printfn "%f : Floating point" f
| _ -> printfn "%s : Not matched." str
parseNumeric "1.1"
parseNumeric "0"
parseNumeric "0.0"
parseNumeric "10"
parseNumeric "Something else"
A saída do exemplo anterior é o seguinte:
1.100000 : Floating point
0 : Integer
0.000000 : Floating point
10 : Integer
Something else : Not matched.
Ao usar padrões active parcial , às vezes, as opções individuais podem ser disjunção ou mutuamente exclusivos, mas eles não precisam ser.No exemplo a seguir, o quadrado do padrão e o cubo de padrão não são disjunção, porque alguns números são quadrados e cubos, como, por exemplo, 64.O seguinte programa imprime todos os inteiros até 1000000 quadrados e cubos.
let err = 1.e-10
let isNearlyIntegral (x:float) = abs (x - round(x)) < err
let (|Square|_|) (x : int) =
if isNearlyIntegral (sqrt (float x)) then Some(x)
else None
let (|Cube|_|) (x : int) =
if isNearlyIntegral ((float x) ** ( 1.0 / 3.0)) then Some(x)
else None
let examineNumber x =
match x with
| Cube x -> printfn "%d is a cube" x
| _ -> ()
match x with
| Square x -> printfn "%d is a square" x
| _ -> ()
let findSquareCubes x =
if (match x with
| Cube x -> true
| _ -> false
&&
match x with
| Square x -> true
| _ -> false
)
then printf "%d \n" x
[ 1 .. 1000000 ] |> List.iter (fun elem -> findSquareCubes elem)
A saída é o seguinte:
1
64
729
4096
15625
46656
117649
262144
531441
1000000
Padrões de ativos com parâmetros
Padrões Active sempre têm pelo menos um argumento para o item que está sendo correspondido, mas podem se argumentos adicionais da mesma forma, em cujo maiúsculas e minúsculas o nome parametrizado padrão ativo se aplica.Argumentos adicionais permitem que um padrão geral ser especializado.Por exemplo, o active padrões que usam expressões regulares para analisar cadeias de caracteres geralmente incluem a expressão regular como um extra parâmetro, como no código a seguir, que também usa o padrão de active parcial Integer definido no exemplo de código anterior.Neste exemplo, seqüências de caracteres que usam expressões regulares para vários formatos de data são fornecidas para personalizar o padrão de active ParseRegex geral.O padrão de active inteiro é usado para converter as cadeias correspondidas em números inteiros que podem ser passados para o construtorde DateTime.
open System.Text.RegularExpressions
// ParseRegex parses a regular expression and returns a list of the strings that match each group in
// the regular expression.
// List.tail is called to eliminate the first element in the list, which is the full matched expression,
// since only the matches for each group are wanted.
let (|ParseRegex|_|) regex str =
let m = Regex(regex).Match(str)
if m.Success
then Some (List.tail [ for x in m.Groups -> x.Value ])
else None
// Three different date formats are demonstrated here. The first matches two-
// digit dates and the second matches full dates. This code assumes that if a two-digit
// date is provided, it is an abbreviation, not a year in the first century.
let parseDate str =
match str with
| ParseRegex "(\d{1,2})/(\d{1,2})/(\d{1,2})$" [Integer m; Integer d; Integer y]
-> new System.DateTime(y + 2000, m, d)
| ParseRegex "(\d{1,2})/(\d{1,2})/(\d{3,4})" [Integer m; Integer d; Integer y]
-> new System.DateTime(y, m, d)
| ParseRegex "(\d{1,4})-(\d{1,2})-(\d{1,2})" [Integer y; Integer m; Integer d]
-> new System.DateTime(y, m, d)
| _ -> new System.DateTime()
let dt1 = parseDate "12/22/08"
let dt2 = parseDate "1/1/2009"
let dt3 = parseDate "2008-1-15"
let dt4 = parseDate "1995-12-28"
printfn "%s %s %s %s" (dt1.ToString()) (dt2.ToString()) (dt3.ToString()) (dt4.ToString())
A saída do código anterior é o seguinte:
12/22/2008 12:00:00 AM 1/1/2009 12:00:00 AM 1/15/2008 12:00:00 AM 12/28/1995 12:00:00 AM
Consulte também
Referência
Expressões de correspondência (F#)