Hesaplama İfadeleri

F# dilindeki hesaplama ifadeleri, denetim akışı yapıları ve bağlamaları kullanılarak sıralanıp birleştirilebilen hesaplamalar yazmak için kullanışlı bir söz dizimi sağlar. Hesaplama ifadesinin türüne bağlı olarak, bunlar manastırları, monoidleri, manastır transformatörlerini ve applicative functor'ları ifade etmenin bir yolu olarak düşünülebilir. Ancak, diğer dillerden farklı olarak (Haskell'de do-ation gibi), bunlar tek bir soyutlamayla bağlantılı değildir ve kullanışlı ve bağlama duyarlı söz dizimini gerçekleştirmek için makrolara veya diğer meta programlama biçimlerine güvenmez.

Genel bakış

Hesaplamalar birçok biçim alabilir. Hesaplamanın en yaygın biçimi, anlaşılması ve değiştirilmesi kolay olan tek iş parçacıklı yürütmedir. Ancak, tüm hesaplama biçimleri tek iş parçacıklı yürütme kadar basit değildir. Bazı Örnekler:

  • Belirlenmeci olmayan hesaplamalar
  • Zaman uyumsuz hesaplamalar
  • Etkili hesaplamalar
  • Üretken hesaplamalar

Daha genel olarak, bir uygulamanın belirli bölümlerinde gerçekleştirmeniz gereken bağlama duyarlı hesaplamalar vardır. Bağlama duyarlı kod yazmak zor olabilir, bu nedenle hesaplamaları soyutlamalar olmadan belirli bir bağlamın dışına "sızdırmak" kolaydır. Bu soyutlamaların tek başına yazılması genellikle zordur, bu nedenle F# hesaplama ifadeleri olarak adlandırılan genelleştirilmiş bir yönteme sahiptir.

Hesaplama ifadeleri, bağlama duyarlı hesaplamaları kodlamak için tekdüzen bir söz dizimi ve soyutlama modeli sunar.

Her hesaplama ifadesi bir oluşturucu türü tarafından desteklenir. Oluşturucu türü, hesaplama ifadesi için kullanılabilen işlemleri tanımlar. Bkz . Özel bir hesaplama ifadesinin nasıl oluşturulacağını gösteren Yeni Bir Hesaplama İfadesi Türü Oluşturma.

Söz dizimine genel bakış

Tüm hesaplama ifadeleri aşağıdaki forma sahiptir:

builder-expr { cexper }

Bu formda, builder-expr hesaplama ifadesini tanımlayan oluşturucu türünün adı ve cexper hesaplama ifadesinin ifade gövdesidir. Örneğin, async hesaplama ifadesi kodu şu şekilde görünebilir:

let fetchAndDownload url =
    async {
        let! data = downloadData url

        let processedData = processData data

        return processedData
    }

Önceki örnekte gösterildiği gibi, hesaplama ifadesinde kullanılabilen özel ve ek bir söz dizimi vardır. Aşağıdaki ifade formları hesaplama ifadeleriyle mümkündür:

expr { let! ... }
expr { and! ... }
expr { do! ... }
expr { yield ... }
expr { yield! ... }
expr { return ... }
expr { return! ... }
expr { match! ... }

Bu anahtar sözcüklerin ve diğer standart F# anahtar sözcüklerinin her biri, yalnızca arka oluşturma oluşturucusu türünde tanımlanmışsa bir hesaplama ifadesinde kullanılabilir. Bunun match!tek istisnası, kullanımı let! için söz dizimsel şeker olan ve ardından sonuç üzerinde bir desen eşleşmesi olan 'dir.

Oluşturucu türü, hesaplama ifadesinin parçalarının birleştirilme şeklini yöneten özel yöntemleri tanımlayan bir nesnedir; yani yöntemleri, hesaplama ifadesinin nasıl davranacağını denetler. Oluşturucu sınıfını açıklamanın bir diğer yolu da döngüler ve bağlamalar gibi birçok F# yapısının çalışmasını özelleştirmenize olanak sağladığını söylemektir.

let!

let! anahtar sözcüğü, çağrının sonucunu başka bir hesaplama ifadesine bir ada bağlar:

let doThingsAsync url =
    async {
        let! data = getDataAsync url
        ...
    }

Çağrısı ile letbir hesaplama ifadesine bağlarsanız, hesaplama ifadesinin sonucunu alamazsınız. Bunun yerine, gerçekleşmemiş çağrının değerini bu hesaplama ifadesine bağlamış olursunuz. Sonucu bağlamak için kullanın let! .

let! oluşturucu türündeki Bind(x, f) üye tarafından tanımlanır.

and!

and! anahtar sözcüğü, birden çok hesaplama ifadesi çağrısının sonuçlarını yüksek performanslı bir şekilde bağlamanıza olanak tanır.

let doThingsAsync url =
    async {
        let! data = getDataAsync url
        and! moreData = getMoreDataAsync anotherUrl
        and! evenMoreData = getEvenMoreDataAsync someUrl
        ...
    }

Pahalı bağlamaların let! ... let! ... yeniden yürütülmesi için bir dizi zorlama kullanıldığından, çok sayıda hesaplama ifadesinin sonuçları bağlanırken kullanılması let! ... and! ... gerekir.

and! öncelikle oluşturucu türündeki MergeSources(x1, x2) üye tarafından tanımlanır.

İsteğe bağlı olarak, MergeSourcesN(x1, x2 ..., xN) tanımlama düğümlerinin sayısını azaltmak için ve BindN(x1, x2 ..., xN, f)veya BindNReturn(x1, x2, ..., xN, f) düğümleri bağlamadan hesaplama ifadesi sonuçlarını verimli bir şekilde bağlamak için tanımlanabilir.

do!

anahtar do! sözcüğü, bir -like türü döndüren unitbir hesaplama ifadesi çağırmak içindir (oluşturucudaki Zero üye tarafından tanımlanır):

let doThingsAsync data url =
    async {
        do! submitData data url
        ...
    }

Zaman uyumsuz iş akışı için bu türdürAsync<unit>. Diğer hesaplama ifadeleri için türü büyük olasılıkla olacaktır CExpType<unit>.

do! oluşturucu türündeki Bind(x, f) üye tarafından tanımlanır ve burada f bir unitoluşturur.

yield

anahtar yield sözcüğü, hesaplama ifadesinden bir değer döndürerek değerinin olarak tüketilmesine yöneliktir IEnumerable<T>:

let squares =
    seq {
        for i in 1..10 do
            yield i * i
    }

for sq in squares do
    printfn $"%d{sq}"

Çoğu durumda, arayanlar tarafından atlanabilir. At etmenin yield en yaygın yolu işlecidir -> :

let squares =
    seq {
        for i in 1..10 -> i * i
    }

for sq in squares do
    printfn $"%d{sq}"

Birçok farklı değer verebilen ve belki de koşullu olarak daha karmaşık ifadeler için, anahtar sözcüğünü atlayarak şunları yapabilirsiniz:

let weekdays includeWeekend =
    seq {
        "Monday"
        "Tuesday"
        "Wednesday"
        "Thursday"
        "Friday"
        if includeWeekend then
            "Saturday"
            "Sunday"
    }

C# dilindeki yield anahtar sözcüğünde olduğu gibi, hesaplama ifadesindeki her öğe yinelendikçe geri döndürülür.

yield oluşturucu türündeki Yield(x) üye tarafından tanımlanır; burada x geri döndürülecek öğedir.

yield!

anahtar yield! sözcüğü, bir hesaplama ifadesinden bir değer koleksiyonunu düzleştirmeye yöneliktir:

let squares =
    seq {
        for i in 1..3 -> i * i
    }

let cubes =
    seq {
        for i in 1..3 -> i * i * i
    }

let squaresAndCubes =
    seq {
        yield! squares
        yield! cubes
    }

printfn $"{squaresAndCubes}"  // Prints - 1; 4; 9; 1; 8; 27

Değerlendirildiğinde, tarafından yield! çağrılan hesaplama ifadesi öğelerinin birer birer geri döndürülerek sonucu düzleştirmesini sağlar.

yield! oluşturucu türündeki YieldFrom(x) üye tarafından tanımlanır ve burada x bir değer koleksiyonudur.

aksine yieldaçıkça yield! belirtilmelidir. Davranış, hesaplama ifadelerinde örtük değildir.

return

return anahtar sözcüğü, hesaplama ifadesine karşılık gelen türdeki bir değeri sarmalar. kullanan yieldhesaplama ifadelerinin yanı sıra, bir hesaplama ifadesini "tamamlamak" için kullanılır:

let req = // 'req' is of type 'Async<data>'
    async {
        let! data = fetch url
        return data
    }

// 'result' is of type 'data'
let result = Async.RunSynchronously req

return , oluşturucu türündeki üye tarafından Return(x) tanımlanır; burada x kaydırılan öğedir. Kullanım için let! ... return gelişmiş BindReturn(x, f) performans için kullanılabilir.

return!

return! anahtar sözcüğü bir hesaplama ifadesinin değerini fark eder ve hesaplama ifadesine karşılık gelen türle sonuçlanır:

let req = // 'req' is of type 'Async<data>'
    async {
        return! fetch url
    }

// 'result' is of type 'data'
let result = Async.RunSynchronously req

return! , oluşturucu türündeki üye tarafından ReturnFrom(x) tanımlanır ve burada x başka bir hesaplama ifadesidir.

match!

match! anahtar sözcüğü, bir çağrıyı başka bir hesaplama ifadesine satır içi olarak eklemenizi ve sonucuyla desen eşleşmesini sağlar:

let doThingsAsync url =
    async {
        match! callService url with
        | Some data -> ...
        | None -> ...
    }

ile match!bir hesaplama ifadesi çağırırken, gibi let!çağrının sonucunu fark eder. Bu genellikle sonucun isteğe bağlı olduğu bir hesaplama ifadesi çağrılırken kullanılır.

Yerleşik hesaplama ifadeleri

F# çekirdek kitaplığı dört yerleşik hesaplama ifadesi tanımlar: Sıralı İfadeler, Zaman Uyumsuz ifadeler, Görev ifadeleri ve Sorgu İfadeleri.

Yeni Bir Hesaplama İfadesi Türü Oluşturma

Oluşturucu sınıfı oluşturup sınıfında belirli özel yöntemleri tanımlayarak kendi hesaplama ifadelerinizin özelliklerini tanımlayabilirsiniz. Oluşturucu sınıfı isteğe bağlı olarak aşağıdaki tabloda listelenen yöntemleri tanımlayabilir.

Aşağıdaki tabloda, bir iş akışı oluşturucu sınıfında kullanılabilecek yöntemler açıklanmaktadır.

Yöntem Tipik imzalar Açıklama
Bind M<'T> * ('T -> M<'U>) -> M<'U> hesaplama ifadelerinde ve let!do! için çağrılır.
BindN (M<'T1> * M<'T2> * ... * M<'TN> * ('T1 * 'T2 ... * 'TN -> M<'U>)) -> M<'U> Girişleri birleştirmeden verimli let! ve and! hesaplama ifadelerinde çağrılır.

örneğin Bind3, Bind4.
Delay (unit -> M<'T>) -> Delayed<'T> Bir hesaplama ifadesini işlev olarak sarmalar. Delayed<'T> yaygın olarak M<'T> veya unit -> M<'T> kullanılan herhangi bir tür olabilir. Varsayılan uygulama bir M<'T>döndürür.
Return 'T -> M<'T> hesaplama ifadelerinde için return çağrılır.
ReturnFrom M<'T> -> M<'T> hesaplama ifadelerinde için return! çağrılır.
BindReturn (M<'T1> * ('T1 -> 'T2)) -> M<'T2> Hesaplama ifadelerinde verimli let! ... return bir şekilde çağrılır.
BindNReturn (M<'T1> * M<'T2> * ... * M<'TN> * ('T1 * 'T2 ... * 'TN -> M<'U>)) -> M<'U> Girişleri birleştirmeden hesaplama ifadelerinde verimli let! ... and! ... return bir şekilde çağrılır.

örneğin Bind3Return, Bind4Return.
MergeSources (M<'T1> * M<'T2>) -> M<'T1 * 'T2> hesaplama ifadelerinde için and! çağrılır.
MergeSourcesN (M<'T1> * M<'T2> * ... * M<'TN>) -> M<'T1 * 'T2 * ... * 'TN> hesaplama ifadelerinde için and! çağrılır, ancak tanımlama düğümlerinin sayısını azaltarak verimliliği artırır.

örneğin MergeSources3, MergeSources4.
Run Delayed<'T> -> M<'T> veya

M<'T> -> 'T
Bir hesaplama ifadesi yürütür.
Combine M<'T> * Delayed<'T> -> M<'T> veya

M<unit> * M<'T> -> M<'T>
Hesaplama ifadelerinde sıralama için çağrıldı.
For seq<'T> * ('T -> M<'U>) -> M<'U> veya

seq<'T> * ('T -> M<'U>) -> seq<M<'U>>
Hesaplama ifadelerindeki ifadeler için for...do çağrılır.
TryFinally Delayed<'T> * (unit -> unit) -> M<'T> Hesaplama ifadelerindeki ifadeler için try...finally çağrılır.
TryWith Delayed<'T> * (exn -> M<'T>) -> M<'T> Hesaplama ifadelerindeki ifadeler için try...with çağrılır.
Using 'T * ('T -> M<'U>) -> M<'U> when 'T :> IDisposable Hesaplama ifadelerindeki bağlamalar için use çağrılır.
While (unit -> bool) * Delayed<'T> -> M<'T>Veya

(unit -> bool) * Delayed<unit> -> M<unit>
Hesaplama ifadelerindeki ifadeler için while...do çağrılır.
Yield 'T -> M<'T> Hesaplama ifadelerindeki ifadeler için yield çağrılır.
YieldFrom M<'T> -> M<'T> Hesaplama ifadelerindeki ifadeler için yield! çağrılır.
Zero unit -> M<'T> Hesaplama ifadelerindeki ifadelerin if...then boş else dalları için çağrılır.
Quote Quotations.Expr<'T> -> Quotations.Expr<'T> Hesaplama ifadesinin üyeye Run tırnak olarak geçirildiğini gösterir. Hesaplamanın tüm örneklerini bir teklife çevirir.

Oluşturucu sınıfındaki yöntemlerin çoğu, örneğin zaman uyumsuz ifadeler ve sıralı iş akışları için birleştirilen Async<'T> hesaplama türlerini karakterize eden ayrı tanımlanmış bir tür olan bir M<'T> yapıyı kullanır ve Seq<'T> döndürür. Bu yöntemlerin imzaları, bir yapıdan döndürülen iş akışı nesnesinin bir sonrakine geçirilebilmesi için bunların birleştirilip iç içe geçirilmesini sağlar.

Birçok işlev, sonucunu Delay bağımsız değişken olarak kullanır: Run, While, TryWith, TryFinallyve Combine. türü Delayed<'T> , ve sonuç olarak bu işlevlerin parametresinin dönüş türüdür Delay . Delayed<'T> ile ilgili M<'T>olması gerekmeyen veya yaygın olarak M<'T>(unit -> M<'T>) kullanılan rastgele bir tür olabilir. Varsayılan uygulama şeklindedir M<'T>. Daha ayrıntılı bir görünüm için buraya bakın.

Derleyici, bir hesaplama ifadesini ayrıştırdığında, önceki tablodaki yöntemleri ve hesaplama ifadesindeki kodu kullanarak ifadeyi bir dizi iç içe işlev çağrısına çevirir. İç içe ifade aşağıdaki biçimdedir:

builder.Run(builder.Delay(fun () -> {{ cexpr }}))

Yukarıdaki kodda, ve çağrıları RunDelay , hesaplama ifadesi oluşturucu sınıfında tanımlanmamışsa atlanır. Burada olarak {{ cexpr }}belirtilen hesaplama ifadesinin gövdesi, oluşturucu sınıfının yöntemlerine yönelik diğer çağrılara çevrilir. Bu işlem, aşağıdaki tabloda yer alan çevirilere göre özyinelemeli olarak tanımlanır. Çift köşeli ayraç içindeki {{ ... }} kod çevrilmeye devam eder, expr F# ifadesini temsil eder ve cexpr bir hesaplama ifadesini temsil eder.

Expression Çeviri
{{ let binding in cexpr }} let binding in {{ cexpr }}
{{ let! pattern = expr in cexpr }} builder.Bind(expr, (fun pattern -> {{ cexpr }}))
{{ do! expr in cexpr }} builder.Bind(expr, (fun () -> {{ cexpr }}))
{{ yield expr }} builder.Yield(expr)
{{ yield! expr }} builder.YieldFrom(expr)
{{ return expr }} builder.Return(expr)
{{ return! expr }} builder.ReturnFrom(expr)
{{ use pattern = expr in cexpr }} builder.Using(expr, (fun pattern -> {{ cexpr }}))
{{ use! value = expr in cexpr }} builder.Bind(expr, (fun value -> builder.Using(value, (fun value -> {{ cexpr }}))))
{{ if expr then cexpr0 }} if expr then {{ cexpr0 }} else builder.Zero()
{{ if expr then cexpr0 else cexpr1 }} if expr then {{ cexpr0 }} else {{ cexpr1 }}
{{ match expr with | pattern_i -> cexpr_i }} match expr with | pattern_i -> {{ cexpr_i }}
{{ for pattern in enumerable-expr do cexpr }} builder.For(enumerable-expr, (fun pattern -> {{ cexpr }}))
{{ for identifier = expr1 to expr2 do cexpr }} builder.For([expr1..expr2], (fun identifier -> {{ cexpr }}))
{{ while expr do cexpr }} builder.While(fun () -> expr, builder.Delay({{ cexpr }}))
{{ try cexpr with | pattern_i -> expr_i }} builder.TryWith(builder.Delay({{ cexpr }}), (fun value -> match value with | pattern_i -> expr_i | exn -> System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(exn).Throw()))
{{ try cexpr finally expr }} builder.TryFinally(builder.Delay({{ cexpr }}), (fun () -> expr))
{{ cexpr1; cexpr2 }} builder.Combine({{ cexpr1 }}, {{ cexpr2 }})
{{ other-expr; cexpr }} expr; {{ cexpr }}
{{ other-expr }} expr; builder.Zero()

Önceki tabloda, other-expr tabloda başka şekilde listelenmeyen bir ifade açıklanmaktadır. Oluşturucu sınıfının tüm yöntemleri uygulaması ve önceki tabloda listelenen tüm çevirileri desteklemesi gerekmez. Uygulanmayan yapılar, bu türdeki hesaplama ifadelerinde kullanılamaz. Örneğin, hesaplama ifadelerinizde anahtar sözcüğünü use desteklemek istemiyorsanız, oluşturucu sınıfınızdaki tanımını Use atlayabilirsiniz.

Aşağıdaki kod örneği, bir hesaplamayı her seferinde bir adım değerlendirilebilecek bir dizi adım olarak kapsülleyen bir hesaplama ifadesini gösterir. Ayrımcı birleşim türü, OkOrExceptionifadenin hata durumunu şu ana kadar değerlendirildiği şekilde kodlar. Bu kod, bazı oluşturucu yöntemlerinin ortak uygulamaları gibi hesaplama ifadelerinizde kullanabileceğiniz çeşitli tipik desenleri gösterir.

/// Represents computations that can be run step by step
type Eventually<'T> =
    | Done of 'T
    | NotYetDone of (unit -> Eventually<'T>)

module Eventually =

    /// Bind a computation using 'func'.
    let rec bind func expr =
        match expr with
        | Done value -> func value
        | NotYetDone work -> NotYetDone (fun () -> bind func (work()))

    /// Return the final value
    let result value = Done value

    /// The catch for the computations. Stitch try/with throughout
    /// the computation, and return the overall result as an OkOrException.
    let rec catch expr =
        match expr with
        | Done value -> result (Ok value)
        | NotYetDone work ->
            NotYetDone (fun () ->
                let res = try Ok(work()) with | exn -> Error exn
                match res with
                | Ok cont -> catch cont // note, a tailcall
                | Error exn -> result (Error exn))

    /// The delay operator.
    let delay func = NotYetDone (fun () -> func())

    /// The stepping action for the computations.
    let step expr =
        match expr with
        | Done _ -> expr
        | NotYetDone func -> func ()

    /// The tryFinally operator.
    /// This is boilerplate in terms of "result", "catch", and "bind".
    let tryFinally expr compensation =
        catch (expr)
        |> bind (fun res ->
            compensation();
            match res with
            | Ok value -> result value
            | Error exn -> raise exn)

    /// The tryWith operator.
    /// This is boilerplate in terms of "result", "catch", and "bind".
    let tryWith exn handler =
        catch exn
        |> bind (function Ok value -> result value | Error exn -> handler exn)

    /// The whileLoop operator.
    /// This is boilerplate in terms of "result" and "bind".
    let rec whileLoop pred body =
        if pred() then body |> bind (fun _ -> whileLoop pred body)
        else result ()

    /// The sequential composition operator.
    /// This is boilerplate in terms of "result" and "bind".
    let combine expr1 expr2 =
        expr1 |> bind (fun () -> expr2)

    /// The using operator.
    /// This is boilerplate in terms of "tryFinally" and "Dispose".
    let using (resource: #System.IDisposable) func =
        tryFinally (func resource) (fun () -> resource.Dispose())

    /// The forLoop operator.
    /// This is boilerplate in terms of "catch", "result", and "bind".
    let forLoop (collection:seq<_>) func =
        let ie = collection.GetEnumerator()
        tryFinally
            (whileLoop
                (fun () -> ie.MoveNext())
                (delay (fun () -> let value = ie.Current in func value)))
            (fun () -> ie.Dispose())

/// The builder class.
type EventuallyBuilder() =
    member x.Bind(comp, func) = Eventually.bind func comp
    member x.Return(value) = Eventually.result value
    member x.ReturnFrom(value) = value
    member x.Combine(expr1, expr2) = Eventually.combine expr1 expr2
    member x.Delay(func) = Eventually.delay func
    member x.Zero() = Eventually.result ()
    member x.TryWith(expr, handler) = Eventually.tryWith expr handler
    member x.TryFinally(expr, compensation) = Eventually.tryFinally expr compensation
    member x.For(coll:seq<_>, func) = Eventually.forLoop coll func
    member x.Using(resource, expr) = Eventually.using resource expr

let eventually = new EventuallyBuilder()

let comp =
    eventually {
        for x in 1..2 do
            printfn $" x = %d{x}"
        return 3 + 4
    }

/// Try the remaining lines in F# interactive to see how this
/// computation expression works in practice.
let step x = Eventually.step x

// returns "NotYetDone <closure>"
comp |> step

// prints "x = 1"
// returns "NotYetDone <closure>"
comp |> step |> step

// prints "x = 1"
// prints "x = 2"
// returns "Done 7"
comp |> step |> step |> step |> step

Hesaplama ifadesi, ifadenin döndürdüğü temel bir türe sahiptir. Temel alınan tür, hesaplanan bir sonucu veya gerçekleştirilebilecek gecikmeli bir hesaplamayı temsil edebilir veya bir tür koleksiyonda yineleme yapmak için bir yol sağlayabilir. Önceki örnekte, temel alınan tür şeklindeydi Eventually<_>. Bir dizi ifadesi için, temel alınan tür şeklindedir System.Collections.Generic.IEnumerable<T>. Sorgu ifadesi için, temel alınan tür şeklindedir System.Linq.IQueryable. Zaman uyumsuz bir ifade için, temel alınan tür şeklindedir Async. nesnesi, Async sonucu hesaplamak için gerçekleştirilecek çalışmayı temsil eder. Örneğin, bir hesaplama yürütmek ve sonucu döndürmek için çağrısında Async.RunSynchronously bulunursunuz.

Özel İşlemler

Bir hesaplama ifadesinde özel bir işlem tanımlayabilir ve özel işlemi bir hesaplama ifadesinde işleç olarak kullanabilirsiniz. Örneğin, sorgu ifadesinde sorgu işleci ekleyebilirsiniz. Özel bir işlem tanımlarken, hesaplama ifadesinde Yield ve For yöntemlerini tanımlamanız gerekir. Özel bir işlem tanımlamak için, bunu hesaplama ifadesi için bir oluşturucu sınıfına yerleştirin ve uygulayın CustomOperationAttribute. Bu öznitelik, özel bir işlemde kullanılacak ad olan bir dizeyi bağımsız değişken olarak alır. Bu ad, hesaplama ifadesinin açılış küme ayracının başlangıcında kapsama girer. Bu nedenle, bu bloktaki özel bir işlemle aynı ada sahip tanımlayıcıları kullanmamalısınız. Örneğin, veya gibi alllast tanımlayıcıların sorgu ifadelerinde kullanılmasından kaçının.

Mevcut Oluşturucuları yeni Özel İşlemlerle genişletme

Zaten bir oluşturucu sınıfınız varsa, özel işlemleri bu oluşturucu sınıfının dışından genişletilebilir. Uzantılar modüllerde bildirilmelidir. Ad alanları, türün tanımlandığı aynı dosya ve aynı ad alanı bildirim grubu dışında uzantı üyeleri içeremez.

Aşağıdaki örnekte mevcut FSharp.Linq.QueryBuilder sınıfın uzantısı gösterilmektedir.

open System
open FSharp.Linq

type QueryBuilder with

    [<CustomOperation("existsNot")>]
    member _.ExistsNot (source: QuerySource<'T, 'Q>, predicate) =
        System.Linq.Enumerable.Any (source.Source, Func<_,_>(predicate)) |> not

Özel işlemler aşırı yüklenebilir. Daha fazla bilgi için bkz . F# RFC FS-1056 - Hesaplama ifadelerinde özel anahtar sözcüklerin aşırı yüklenmesine izin verme.

Hesaplama ifadelerini verimli bir şekilde derleme

Yürütmeyi askıya alan F# hesaplama ifadeleri, devam ettirilebilir kod olarak adlandırılan düşük düzeyli bir özelliği dikkatli bir şekilde kullanarak son derece verimli durum makinelerine derlenebilir. Devam ettirilebilen kod F# RFC FS-1087'de belgelenmiştir ve Görev İfadeleri için kullanılır.

Zaman uyumlu olan F# hesaplama ifadeleri (yani yürütmeyi askıya almaz), alternatif olarak özniteliği de dahil olmak üzere satır içi işlevler kullanılarak verimli durum makinelerine InlineIfLambda derlenebilir. Örnekler F# RFC FS-1098'de verilmiştir.

Liste ifadeleri, dizi ifadeleri ve sıra ifadeleri, yüksek performanslı kodun oluşturulmasını sağlamak için F# derleyicisi tarafından özel bir işlem uygulanır.

Ayrıca bkz.