Etkin Desenler
Etkin desenler , giriş verilerini alt bölümlere ayıracak adlandırılmış bölümler tanımlamanızı sağlar, böylece bu adları ayrımcı birleşimde olduğu gibi bir desen eşleştirme ifadesinde kullanabilirsiniz. Verileri her bölüm için özelleştirilmiş bir şekilde ayrıştırmak için etkin desenler kullanabilirsiniz.
Sözdizimi
// Active pattern of one choice.
let (|identifier|) [arguments] valueToMatch = expression
// Active Pattern with multiple choices.
// Uses a FSharp.Core.Choice<_,...,_> based on the number of case names. In F#, the limitation n <= 7 applies.
let (|identifier1|identifier2|...|) valueToMatch = expression
// Partial active pattern definition.
// Uses a FSharp.Core.option<_> to represent if the type is satisfied at the call site.
let (|identifier|_|) [arguments] valueToMatch = expression
Açıklamalar
Önceki söz diziminde tanımlayıcılar, bağımsız değişkenlerle temsil edilen giriş verilerinin bölümlerinin adları veya diğer bir deyişle bağımsız değişkenlerin tüm değerleri kümesinin alt kümelerinin adlarıdır. Etkin desen tanımında en fazla yedi bölüm olabilir. İfade, verilerin ayrıştırıldığı formu açıklar. Bağımsız değişken olarak verilen değerlerin hangi adlandırılmış bölümlere ait olduğunu belirleme kurallarını tanımlamak için etkin bir desen tanımı kullanabilirsiniz. (| ve |) simgeleri muz klipleri olarak adlandırılır ve bu tür izin bağlaması tarafından oluşturulan işlev etkin tanıyıcı olarak adlandırılır.
Örneğin, bağımsız değişken içeren aşağıdaki etkin deseni göz önünde bulundurun.
let (|Even|Odd|) input = if input % 2 = 0 then Even else Odd
Aşağıdaki örnekte olduğu gibi bir desen eşleştirme ifadesinde etkin deseni kullanabilirsiniz.
let TestNumber input =
match input with
| Even -> printfn "%d is even" input
| Odd -> printfn "%d is odd" input
TestNumber 7
TestNumber 11
TestNumber 32
Bu programın çıktısı aşağıdaki gibidir:
7 is odd
11 is odd
32 is even
Etkin desenlerin bir diğer kullanımı da veri türlerini, örneğin aynı temel alınan verilerin çeşitli olası gösterimlerine sahip olması gibi çeşitli yollarla ayrıştırmaktır. Örneğin, bir Color
nesne RGB gösterimine veya HSB gösterimine bölünebilir.
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"
Yukarıdaki programın çıkışı aşağıdaki gibidir:
Red
Red: 255 Green: 0 Blue: 0
Hue: 360.000000 Saturation: 1.000000 Brightness: 0.500000
Black
Red: 0 Green: 0 Blue: 0
Hue: 0.000000 Saturation: 0.000000 Brightness: 0.000000
White
Red: 255 Green: 255 Blue: 255
Hue: 0.000000 Saturation: 0.000000 Brightness: 1.000000
Gray
Red: 128 Green: 128 Blue: 128
Hue: 0.000000 Saturation: 0.000000 Brightness: 0.501961
BlanchedAlmond
Red: 255 Green: 235 Blue: 205
Hue: 36.000000 Saturation: 1.000000 Brightness: 0.901961
Birlikte, etkin desenleri kullanmanın bu iki yolu, verileri yalnızca uygun biçimde bölümlemenize ve ayrıştırmanıza ve uygun veriler üzerinde hesaplama için en uygun biçimde uygun hesaplamaları gerçekleştirmenize olanak tanır.
Sonuçta elde edilen desen eşleştirme ifadeleri, verilerin çok okunabilir ve karmaşık olabilecek dallanma ve veri çözümleme kodunu büyük ölçüde basitleştiren kullanışlı bir şekilde yazılabilmesini sağlar.
Kısmi Etkin Desenler
Bazen, giriş alanının yalnızca bir bölümünü bölümlemeniz gerekir. Bu durumda, her biri bazı girişlerle eşleşen ancak diğer girişlerle eşleşmeyen kısmi desenler kümesi yazarsınız. Her zaman değer üretmeyen etkin desenler kısmi etkin desenler olarak adlandırılır; seçenek türü olan bir dönüş değerine sahiptir. Kısmi etkin desen tanımlamak için, muz klipleri içindeki desen listesinin sonunda bir joker karakter (_) kullanırsınız. Aşağıdaki kodda kısmi etkin desen kullanımı gösterilmektedir.
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"
Önceki örneğin çıktısı aşağıdaki gibidir:
1.100000 : Floating point
0 : Integer
0.000000 : Floating point
10 : Integer
Something else : Not matched.
Kısmi etkin desenler kullanılırken, bazen tek tek seçenekler kopuk veya birbirini dışlayabilir, ancak gerekli değildir. Aşağıdaki örnekte, bazı sayılar 64 gibi kareler ve küpler olduğundan Kare deseni ve desen Küpü kopuk değildir. Aşağıdaki program, Kare ve Küp desenlerini birleştirmek için AND desenini kullanır. Hem kare hem de küp olan 1000'e kadar olan tüm tamsayıların yanı sıra yalnızca küp olan tamsayıları yazdırır.
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 findSquareCubes x =
match x with
| Cube x & Square _ -> printfn "%d is a cube and a square" x
| Cube x -> printfn "%d is a cube" x
| _ -> ()
[ 1 .. 1000 ] |> List.iter (fun elem -> findSquareCubes elem)
Çıktı aşağıdaki şekilde olacaktır:
1 is a cube and a square
8 is a cube
27 is a cube
64 is a cube and a square
125 is a cube
216 is a cube
343 is a cube
512 is a cube
729 is a cube and a square
1000 is a cube
Parametreli Etkin Desenler
Etkin desenler, eşleştirilen öğe için her zaman en az bir bağımsız değişken alır, ancak bunlar da ek bağımsız değişkenler alabilir ve bu durumda ad parametreli etkin desen uygulanır. Ek bağımsız değişkenler, genel bir desenin özelleştirilebilir olmasını sağlar. Örneğin, dizeleri ayrıştırmak için normal ifadeler kullanan etkin desenler genellikle normal ifadeyi, önceki kod örneğinde tanımlanan kısmi etkin deseni Integer
de kullanan aşağıdaki kodda olduğu gibi ek parametre olarak içerir. Bu örnekte, genel ParseRegex etkin desenini özelleştirmek için çeşitli tarih biçimleri için normal ifadeler kullanan dizeler verilmiştir. Tamsayı etkin deseni, eşleşen dizeleri DateTime oluşturucusuna geçirilebilen tamsayılara dönüştürmek için kullanılır.
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())
Önceki kodun çıkışı aşağıdaki gibidir:
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
Etkin desenler yalnızca desen eşleştirme ifadeleriyle sınırlı değildir, bunları let-binding'lerde de kullanabilirsiniz.
let (|Default|) onNone value =
match value with
| None -> onNone
| Some e -> e
let greet (Default "random citizen" name) =
printfn "Hello, %s!" name
greet None
greet (Some "George")
Önceki kodun çıkışı aşağıdaki gibidir:
Hello, random citizen!
Hello, George!
Ancak yalnızca tek durumlu etkin desenlerin parametrelendirilebileceğini unutmayın.
// A single-case partial active pattern can be parameterized
let (| Foo|_|) s x = if x = s then Some Foo else None
// A multi-case active patterns cannot be parameterized
// let (| Even|Odd|Special |) (s: int) (x: int) = if x = s then Special elif x % 2 = 0 then Even else Odd
Kısmi Etkin Desenler için Yapı Gösterimleri
Varsayılan olarak, kısmi etkin desenler başarılı bir option
eşleşmedeki Some
değer için ayırmayı içeren bir değer döndürür. Alternatif olarak, özniteliğini kullanarak Struct
bir değer seçeneğini dönüş değeri olarak kullanabilirsiniz:
open System
[<return: Struct>]
let (|Int|_|) str =
match Int32.TryParse(str) with
| (true, n) -> ValueSome n
| _ -> ValueNone
Bir yapı dönüşünün kullanımı yalnızca dönüş türünün ValueOption
olarak değiştirilmesinden çıkarılmadığından özniteliği belirtilmelidir. Daha fazla bilgi için bkz . RFC FS-1039.