Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
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 monadları, monoidleri, monad transformatörlerini ve uygulayıcı fonksiyonları 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ı işlemdir. Ancak, tüm hesaplama biçimleri tek iş parçacıklı işlem kadar basit değildir. Bazı örnekler şunlardır:
- 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 tek istisnası, match! kullanımı için bir tür sözdizimsel kolaylık olan let! ve sonuç üzerinde bir desen eşleştirmesi yapılmasıdır.
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 ifadesiyle bir isimle ilişkilendirir.
let doThingsAsync url =
async {
let! data = getDataAsync url
...
}
Bir çağrıyı let bir hesaplama ifadesine bağlayacak olursanız, hesaplama ifadesinin sonucunu alamazsınız. Bunun yerine, gerçekleşmemiş çağrının değerini bu hesaplama ifadesine bağlamış olursunuz. Sonuca bağlanmak için let!'yi kullanın.
let! oluşturucu türündeki Bind(x, f) üye tarafından tanımlanır.
and!
anahtar and! sözcüğü, birden çok hesaplama ifadesi çağrısının sonuçlarını daha verimli bağlamanıza olanak tanır. Bu anahtar sözcük, standart monadik yaklaşımdan farklı bir hesaplama modeli sağlayan uygulamalı hesaplama ifadelerini etkinleştirir.
let doThingsAsync url =
async {
let! data = getDataAsync url
and! moreData = getMoreDataAsync anotherUrl
and! evenMoreData = getEvenMoreDataAsync someUrl
...
}
Bir dizi let! ... let! ... kullanmak, bağımsız olsalar bile hesaplamaları sırayla yürütür. Buna karşılık, let! ... and! ... hesaplamaların bağımsız olduğunu gösterir ve uygulamalı birleşime izin verir. Bu bağımsızlık, hesaplama ifadesi yazarlarının şunları yapmasına olanak tanır:
- Hesaplamaları daha verimli bir şekilde yürütür.
- Hesaplamaları paralel olarak çalıştırabilir.
- Gereksiz sıralı bağımlılıklar olmadan sonuçları biriktirin.
Kısıtlama, ile and! birleştirilen hesaplamaların aynı let!/and! zincirdeki daha önce bağlı olan değerlerin sonuçlarına bağımlı olmamalarıdır. Bu denge, performans avantajlarını sağlar.
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.
Uygulamalı hesaplama ifadeleri hakkında daha fazla bilgi için bkz. F# 5 ve F# RFC FS-1063'teUygulamalı Hesaplama İfadeleri.
do!
anahtar kelime do! benzeri bir tür döndüren unit bir 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ür şöyledir: Async<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 kelime yield, hesaplama ifadesi aracılığıyla bir değer döndürerek bir IEnumerable<T> olarak kullanılabilmesi içindir.
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.
yield 'i atlamanın en yaygın yolu -> işleci ile yapılır.
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, yield! tarafından çağrılan hesaplama ifadesi, öğelerini birer birer geri döndürerek sonucu düzleştirir.
yield! oluşturucu türündeki YieldFrom(x) üye tarafından tanımlanır ve burada x bir değer koleksiyonudur.
yield'nın aksine, yield! açıkça 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 Return(x) üyesi tarafından tanımlanır ve burada x, sarılacak öğedir.
let! ... return kullanımı için, performansı artırmak amacıyla BindReturn(x, f) kullanılabilir.
return!
return! anahtar sözcüğü bir hesaplama ifadesinin değerini gerçekleştirir ve bu sonucu hesaplama ifadesine karşılık gelen türde sarar.
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üğü, başka bir hesaplama ifadesini çağırmayı satır içi hale getirmenize ve sonucunu desen eşlemesi yaparak kontrol etmenize olanak tanır.
let doThingsAsync url =
async {
match! callService url with
| Some data -> ...
| None -> ...
}
match! ile bir hesaplama ifadesi çağırdığınızda, çağrının sonucunu let! gibi gerçekleştirir. 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öntemi | Tipik imzalar | Açıklama |
|---|---|---|
Bind |
M<'T> * ('T -> M<'U>) -> M<'U> |
let! ve do! hesaplama ifadelerinde ç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 return için çağrılır. |
ReturnFrom |
M<'T> -> M<'T> |
Hesaplama ifadelerinde return! için çağrılır. |
ReturnFromFinal |
M<'T> -> M<'T> |
Varsa, için ve do! kuyruk çağrısı konumundayken çağrılırreturn!. |
BindReturn |
(M<'T1> * ('T1 -> 'T2)) -> M<'T2> |
Hesaplama ifadelerinde let! ... return verimli bir şekilde çağrılır. |
BindNReturn |
(M<'T1> * M<'T2> * ... * M<'TN> * ('T1 * 'T2 ... * 'TN -> M<'U>)) -> M<'U> |
Hesaplama ifadelerinde girişleri birleştirmeden verimli let! ... and! ... return kullanılmasını gerektirir.örneğin, Bind3Return, Bind4Return. |
MergeSources |
(M<'T1> * M<'T2>) -> M<'T1 * 'T2> |
Hesaplama ifadelerinde and! için çağrılır. |
MergeSourcesN |
(M<'T1> * M<'T2> * ... * M<'TN>) -> M<'T1 * 'T2 * ... * 'TN> |
hesaplama ifadelerinde and! çağrılır, ancak demetleme düğümlerinin sayısını azaltarak verimliliği artırır.örneğin, MergeSources3, MergeSources4. |
Run |
Delayed<'T> -> M<'T> veyaM<'T> -> 'T |
Bir hesaplama ifadesi yürütür. |
Combine |
M<'T> * Delayed<'T> -> M<'T> veyaM<unit> * M<'T> -> M<'T> |
Hesaplama ifadelerinde sıralama işlemi için kullanılır. |
For |
seq<'T> * ('T -> M<'U>) -> M<'U> veyaseq<'T> * ('T -> M<'U>) -> seq<M<'U>> |
Hesaplama ifadelerinde for...do ifadeleri çağırılır. |
TryFinally |
Delayed<'T> * (unit -> unit) -> M<'T> |
Hesaplama ifadelerinde try...finally ifadeleri çağırılır. |
TryWith |
Delayed<'T> * (exn -> M<'T>) -> M<'T> |
Hesaplama ifadelerinde try...with ifadeleri ç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 ifadelerinde while...do ifadeleri çağırılır. |
Yield |
'T -> M<'T> |
Hesaplama ifadelerinde yield ifadeleri çağırılır. |
YieldFrom |
M<'T> -> M<'T> |
Hesaplama ifadelerinde yield! ifadeleri çağırılır. |
YieldFromFinal |
M<'T> -> M<'T> |
Varsa, tail-call konumunda olduğunda ve do! tail-call konumunda olduğunda için geri dönüş olarak çağrılır yield!ReturnFromFinal |
Zero |
unit -> M<'T> |
Hesaplama ifadelerindeki else ifadelerin boş if...then dalları için çağrılır. |
Quote |
Quotations.Expr<'T> -> Quotations.Expr<'T> |
Hesaplama ifadesinin alıntı olarak Run üyeye geçirildiğini gösterir. Hesaplamanın tüm örneklerini alıntıya ç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ştirilmiş hesaplama türlerini karakterize eden, genellikle ayrı tanımlanmış bir tür olan M<'T> yapısını kullanır ve 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, TryFinally ve Combine.
Delayed<'T> türü, Delay'in dönüş türü ve bu işlevlerin parametresi olarak kullanılır.
Delayed<'T> ile M<'T> ile ilgili olması gerekmez; çoklukla M<'T> veya (unit -> M<'T>) kullanılır. Varsayılan uygulama şeklindedir M<'T>. Daha ayrıntılı bir görünüm için bkz. Tür kısıtlamalarını anlama.
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, Run ve Delay çağrıları, hesaplama ifadesi oluşturucu sınıfında tanımlanmamışsa atlanır. Burada belirtildiği gibi {{ cexpr }} olan hesaplama ifadesinin gövdesi, oluşturucu sınıfının yöntemlerine yönelik diğer çağrılara dönüştürülür. 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.
| İfade | Ç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. Altta yatan tür, hesaplanmış bir sonucu veya gerçekleştirilebilecek gecikmeli bir hesaplamayı temsil edebilir ya da bir koleksiyon türü üzerinde tekrarlama yapmak için bir yol sağlayabilir. Önceki örnekte, temel tür Eventually<_> idi. Bir dizi ifadesi için, temel tür System.Collections.Generic.IEnumerable<T>'dir. Sorgu ifadesi için temel alınan tür System.Linq.IQueryable'dir. Zaman uyumsuz bir ifade için, temel alınan tür Async'dir. 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 bir hesaplama ifadesi oluşturucu sınıfına yerleştirin ve ardından CustomOperationAttribute'i uygulayın. 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, all veya last gibi 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ıları gösterilmektedir.
open System
open FSharp.Linq
type QueryBuilder with
[<CustomOperation>]
member _.any (source: QuerySource<'T, 'Q>, predicate) =
System.Linq.Enumerable.Any (source.Source, Func<_,_>(predicate))
[<CustomOperation("singleSafe")>] // you can specify your own operation name in the constructor
member _.singleOrDefault (source: QuerySource<'T, 'Q>, predicate) =
System.Linq.Enumerable.SingleOrDefault (source.Source, Func<_,_>(predicate))
Ö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), satır içi işlevler ve InlineIfLambda özelliği kullanılarak verimli bir şekilde durum makinelerine 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.