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.
anahtar rec sözcüğü, özyinelemeli bir işlev tanımlamak için anahtar sözcüğüyle let birlikte kullanılır.
Sözdizimi
// Recursive function:
let rec function-name parameter-list =
function-body
// Mutually recursive functions:
let rec function1-name parameter-list =
function1-body
and function2-name parameter-list =
function2-body
...
Açıklamalar
Özyinelemeli işlevler - kendilerini çağıran işlevler - F# dilinde anahtar sözcüğüyle rec açıkça tanımlanır.
rec anahtar sözcüğü, bağlamanın let adını gövdesinde kullanılabilir hale getirir.
Aşağıdaki örnekte, matematiksel tanımı kullanarak n. Fibonacci sayısını hesaplayan özyinelemeli bir işlev gösterilmektedir.
let rec fib n =
match n with
| 0 | 1 -> n
| n -> fib (n-1) + fib (n-2)
Uyarı
Uygulamada, önceki örneğe benzer kodlar, önceden hesaplanmış değerleri gereksiz yere yeniden derlediğinden ideal değildir. Bunun nedeni, bu makalede daha ayrıntılı olarak açıklanan kuyruk özyinelemeli olmamasıdır.
Yöntemler, tanımlandığı tür içinde örtük olarak özyinelemeli olur, yani anahtar sözcüğü eklemeye rec gerek yoktur. Örneğin:
type MyClass() =
member this.Fib(n) =
match n with
| 0 | 1 -> n
| n -> this.Fib(n-1) + this.Fib(n-2)
let ancak sınıflar içindeki bağlamalar örtük olarak özyinelemeli değildir. Tüm letbağlı işlevler anahtar sözcüğünü rec gerektirir.
Kuyruk özyineleme
Bazı özyinelemeli işlevler için, kuyruk özyinelemeli olan bir tanım için daha "saf" bir tanımın yeniden düzenlenmesi gerekir. Bu, gereksiz yeniden hesaplamaları önler. Örneğin, önceki Fibonacci sayı oluşturucu aşağıdaki gibi yeniden yazılabilir:
let fib n =
let rec loop acc1 acc2 n =
match n with
| 0 -> acc1
| 1 -> acc2
| _ ->
loop acc2 (acc1 + acc2) (n - 1)
loop 0 1 n
Fibonacci sayısı oluşturmak, matematiksel açıdan saf ancak pratikte verimsiz bir "saf" algoritmanın harika bir örneğidir. Bu daha karmaşık bir uygulama olsa da, çeşitli yönleri F# dilinde verimli olmasını sağlarken özyinelemeli olarak tanımlanmaya devam eder:
- Idiomatic F# deseni olan adlı
loopözyinelemeli bir iç işlev. - Özyinelemeli çağrılara birikmiş değerleri geçiren iki biriktirici parametresi.
- Değerinin
nbelirli bir akümülatör döndürmek için denetlenmesi.
Bu örnek döngüyle yinelemeli olarak yazıldıysa kod, belirli bir koşul karşılanana kadar sayıları toplayan iki farklı değerle benzer görünür.
Bunun kuyruk özyinelemeli olmasının nedeni, özyinelemeli çağrının çağrı yığınında herhangi bir değer kaydetmesi gerekmemesidir. Hesaplanan tüm ara değerler, iç işleve girişler aracılığıyla birikir. Bu ayrıca F# derleyicisinin kodu döngü gibi bir while şey yazmışsınız gibi hızlı olacak şekilde iyileştirmesini sağlar.
Önceki örnekte gösterildiği gibi, bir şeyi iç ve dış işlevle özyinelemeli olarak işleyen F# kodu yazmak yaygındır. İç işlev kuyruk özyinelemesi kullanırken dış işlevi çağıranlar için daha iyi bir arabirime sahiptir.
F# 8.0'dan başlayarak, derleyiciye kuyruk özyinelemeli bir işlev tanımlama amacınızı açıkça belirtmek için özniteliğini kullanabilirsiniz TailCall . İşleviniz kuyruk dışı özyinelemeli çağrılar yaparsa derleyici sizi uyarır. özniteliklerini yöntemlerde ve modül düzeyinde işlevlerde kullanabilirsiniz.
Örneğin, bunu ilk fib tanımda kullanmak:
[<TailCall>]
let rec fib n =
match n with
| 0 | 1 -> n
| n -> fib (n-1) + fib (n-2)
, kuyruk özyinelemeli olmayan iki çağrı hakkında derleyici uyarılarını tetikler.
Karşılıklı Özyinelemeli İşlevler
Bazen işlevler karşılıklı özyinelemeli olur, yani çağrılar bir daire oluşturur ve bu da bir işlevin başka bir işlevi çağırdığı ve aralarında herhangi bir sayıda çağrının bulunduğu ilk işlevi çağırdığı bir dairedir. Bu tür işlevleri birbirine bağlamak için anahtar sözcüğünü kullanarak tek bir let bağlamada and birlikte tanımlamanız gerekir.
Aşağıdaki örnekte karşılıklı özyinelemeli iki işlev gösterilmektedir.
let rec Even x = if x = 0 then true else Odd(x - 1)
and Odd x = if x = 0 then false else Even(x - 1)
Özyinelemeli değerler
Özyinelemeli olması için bir -bound değeri de tanımlayabilirsiniz let. Bu işlem bazen günlüğe kaydetme için yapılır. F# 5 ve işleviyle nameof şunları yapabilirsiniz:
let rec nameDoubles = nameof nameDoubles + nameof nameDoubles