Ayrılmış Birleşimler (F#)
Ayrılmış birleşimler, her biri farklı değerde ve türde olabilen birkaç adlandırılmış çalışmadan biri olabilecek değeri destekler.Ayrılmış birleşimler heterojen veriler için yararlıdır; geçersiz ve hatalı çalışmalar da dahil olmak üzere özel çalışmalara sahip veriler, bir örnekten diğerine tür olarak değişiklik gösteren veriler ve küçük nesne hiyerarşileri için alternatif olan veriler.Buna ek olarak, özyinelemeli ayırt edici birleşimler ağaç veri yapılarını temsil etmek için kullanılır.
type type-name =
| case-identifier1 [of [ fieldname1 : ] type1 [ * [ fieldname2 : ] type2 ...]
| case-identifier2 [of [fieldname3 : ]type3 [ * [ fieldname4 : ]type4 ...]
...
Notlar
Ayrılmış birleşimler, diğer dillerdeki birleşim türleriyle benzerdir, ancak bazı farklılıklar vardır.C++ içindeki birleşim türünde veya Visual Basic içindeki değişken türünde olduğu gibi değerde depolanan veriler sabit değildir, ayrı ayrı birkaç seçenekten biri olabilir.Ancak, diğer bu dillerdeki birleşimlerden farklı olarak, olası seçeneklerin her birine bir durum tanımlayıcı verilir.Durum tanımlayıcıları, bu türden nesnelerin olabileceği çeşitli değer türlerinin adlarıdır; değerler isteğe bağlıdır.Değerler mevcut değilse vaka bir numaralandırma vakasına eşdeğerdir.Değerler varsa her değer belirtilen bir türün tek bir değeri ya da aynı ya da farklı türlerin birden çok alanını toplayan bir kayıt düzeni olabilir.F# 3.1'den itibaren aynı durumdaki diğer alanlar adlandırılmış olsa dahi ayrı ayrı alanlara bir ad verebilirsiniz ancak ad isteğe bağlıdır.
Örneğin, bir Şekil türünün aşağıdaki bildirimini düşünün.
type Shape =
| Rectangle of width : float * length : float
| Circle of radius : float
| Prism of width : float * float * height : float
Önceki kod, şu üç durumdan birine ait değerler içerebilen ayrılmış bir birleşim Şeklini bildirir: Dikdörtgen, Daire ve Prizma.Her örnek farklı bir alan kümesine sahiptir.Dikdörtgen durumunun, genişlik ve uzunluk adlarına sahip ve her ikisi de float türünde, adlandırılmış iki alanı vardır.Circle durumu yalnızca tek bir adlandırılmış alana sahiptir, yarıçap.Prism durumunun üç alanı vardır, ikisi Adlandırılmamış adıyla adlandırılır ve anonim alan olarak tanımlanırlar.
Aşağıdaki örnekler göre adlandırılmış ve anonim alanlar için değerleri sağlayarak nesneleri oluşturuyorsunuz.
let rect = Rectangle(length = 1.3, width = 10.0)
let circ = Circle (1.0)
let prism = Prism(5., 2.0, height = 3.0)
Bu kod, başlatma işlemindeki adlandırılmış alanları kullanabileceğinizi veya bildirimdeki alanların sıralamasını kullanabileceğinizi gösterir ve sonuçta her alan için değerler sağlar.Önceki kodda rect için oluşturucu çağrısı adlandırılmış alanları kullanır, ancak circ için oluşturucu çağrısı sıralamayı kullanır.prism yapısında olduğu gibi sıralanan alanları ve adlandırılan alanları karıştırabilirsiniz.
option türü, F# çekirdek kitaplığında basit bir ayrılmış birleşimdir.option type türü aşağıdaki gibi bildirilir.
// The option type is a discriminated union.
type Option<'a> =
| Some of 'a
| None
Önceki kod Option türünün iki durumu olan ayrılmış bir birleşim olduğunu belirtir; Some ve None.Some durumunun, türü 'a tür parametresi ile belirtilen bir anonim alan içeren ilişkili değeri vardır.None örneğinde ilişkili bir değer yok.Bu nedenle option türü, bir tür değeri olan veya hiç değeri olmayan bir genel tür belirtir.Option türünün bir de option olarak daha sık kullanılan ve küçük harfle yazılan bir diğer adı vardır.
Durum tanımlayıcıları, ayrılmış birleşim türü için oluşturucu olarak kullanılabilir.Örneğin aşağıdaki kod option türü değerler oluşturmak için kullanılır.
let myOption1 = Some(10.0)
let myOption2 = Some("string")
let myOption3 = None
Durum tanımlayıcıları da desen eşleştirme ifadelerinde kullanılır.Bir desen eşleme ifadesinde, tanımlayıcılar tek tek durumlarla ilişkili değerler için sağlanır.Örneğin aşağıdaki kodda x, değerin option türünün Some vakası ile ilişkili olduğu varsayılırsa tanımlayıcıdır.
let printValue opt =
match opt with
| Some x -> printfn "%A" x
| None -> printfn "No value."
Desen eşleştirme ifadelerinde, ayrılmış birleşim eşleşmelerini belirtmek için adlandırılmış alanları kullanabilirsiniz.Daha önceden bildirilen şekil türü için, ad alanlarını alanların değerlerini ayıklamak için aşağıdaki kodun gösterdiği şekilde kullanabilirsiniz.
let getShapeHeight shape =
match shape with
| Rectangle(height = h) -> h
| Circle(radius = r) -> 2. * r
| Prism(height = h) -> h
Normalde, büyük/küçük harf tanımlayıcıları, birleşim adıyla nitelemeden kullanılabilir.Adın her zaman için birleşim adıyla nitelenmesini istiyorsanız, RequireQualifiedAccess özniteliğini birleşim türü tanımına uygulayabilirsiniz.
Nesne Hiyerarşileri Yerine Ayrılmış Birleşimleri Kullanma
Genellikle ayrılmış birleşik yapısını küçük nesne hiyerarşisi için basit bir alternatif olarak kullanabilirsiniz.Örneğin aşağıdaki ayrılmış bileşim, daire, kare ve benzeri türetilmiş türlere sahip bir Shape taban sınıfı yerine kullanılabilir.
type Shape =
// The value here is the radius.
| Circle of float
// The value here is the side length.
| EquilateralTriangle of double
// The value here is the side length.
| Square of double
// The values here are the height and width.
| Rectangle of double * double
Bir alan veya çevre hesaplamak için nesne yönelimli bir uygulamada kullandığınız gibi sanal bir yöntem kullanmak yerine, bu miktarları hesaplamak için uygun formüllere dallanacak desen eşleştirmesi kullanabilirsiniz.Aşağıdaki örnekte, şekile bağlı olarak farklı formüller alanı hesaplamak için kullanılır.
let pi = 3.141592654
let area myShape =
match myShape with
| Circle radius -> pi * radius * radius
| EquilateralTriangle s -> (sqrt 3.0) / 4.0 * s * s
| Square s -> s * s
| Rectangle (h, w) -> h * w
let radius = 15.0
let myCircle = Circle(radius)
printfn "Area of circle that has radius %f: %f" radius (area myCircle)
let squareSide = 10.0
let mySquare = Square(squareSide)
printfn "Area of square that has side %f: %f" squareSide (area mySquare)
let height, width = 5.0, 10.0
let myRectangle = Rectangle(height, width)
printfn "Area of rectangle that has height %f and width %f is %f" height width (area myRectangle)
Çıktı aşağıdaki gibidir:
Area of circle that has radius 15.000000: 706.858347
Area of square that has side 10.000000: 100.000000
Area of rectangle that has height 5.000000 and width 10.000000 is 50.000000
Ağaç Veri Yapıları için Ayrılmış Birleşimler Kullanma
Ayrılmış birleşimler can özyinelemeli olabilir yani birleşim kendi başına bir veya daha fazla çalışma türüne dahil edilebilir.Özyinelemeli ayrılmış birleşimler, programlama dillerindeki ifadeleri modellemek üzere kullanılan ağaç yapıları oluşturmak için kullanılabilir.Aşağıdaki kodda, bir özyinelemeli ayrılmış birlik bir ikili ağaç veri yapısı oluşturmak için kullanılır.Birleşim iki durumdan oluşur; bir tamsayı değeri ile sol ve sağ alt ağaçlara sahip bir düğüm olan Node ve ağacı sonlandıran Tip.
type Tree =
| Tip
| Node of int * Tree * Tree
let rec sumTree tree =
match tree with
| Tip -> 0
| Node(value, left, right) ->
value + sumTree(left) + sumTree(right)
let myTree = Node(0, Node(1, Node(2, Tip, Tip), Node(3, Tip, Tip)), Node(4, Tip, Tip))
let resultSumTree = sumTree myTree
Önceki kodda, resultSumTree 10 değerine sahiptir.Aşağıdaki resimde, myTree için ağaç yapısı gösterilmektedir.
MyTree için ağaç yapısı
Ayrılmış birleşimler, ağaçtaki düğümler heterojense iyi çalışır.Aşağıdaki kodda, Expression türü sayıların ve değişkenlerin toplanmasını ve çarpılmasını destekleyen basit bir programlama dilindeki ifadenin soyut sözdizimi ağacını temsil eder.Bazı birleşim durumları özyinelemeli değildir ve sayıları (Number) veya değişkenler (Variable) temsil eder.Diğer durumlarda özyinelemelidir ve işlenenlerin de deyimler olduğu, işlemleri (Add ve Multiply) temsil eder.Evaluate işlevinde, sözdizimi ağacını yinelemeli olarak işlemek için bir eşleme ifadesi kullanılır.
type Expression =
| Number of int
| Add of Expression * Expression
| Multiply of Expression * Expression
| Variable of string
let rec Evaluate (env:Map<string,int>) exp =
match exp with
| Number n -> n
| Add (x, y) -> Evaluate env x + Evaluate env y
| Multiply (x, y) -> Evaluate env x * Evaluate env y
| Variable id -> env.[id]
let environment = Map.ofList [ "a", 1 ;
"b", 2 ;
"c", 3 ]
// Create an expression tree that represents
// the expression: a + 2 * b.
let expressionTree1 = Add(Variable "a", Multiply(Number 2, Variable "b"))
// Evaluate the expression a + 2 * b, given the
// table of values for the variables.
let result = Evaluate environment expressionTree1
Bu kod yürütüldüğünde, result değeri 5 olur.