Anonim özyineleme - Anonymous recursion

İçinde bilgisayar Bilimi, anonim özyineleme dır-dir özyineleme isme göre bir işlevi açıkça çağırmaz. Bu, açık bir şekilde, bir üst düzey işlev - bir işlevi argüman olarak iletmek ve çağırmak - veya örtük olarak, yansıma mevcut içeriğe bağlı olarak belirli işlevlere, özellikle "geçerli işlev" veya bazen "geçerli işlevin çağıran işlevi" ne erişilmesine izin veren özellikler.

Programlama pratiğinde, anonim özyineleme özellikle JavaScript, onu desteklemek için yansıtma olanakları sağlayan. Genel programlama pratiğinde, bununla birlikte, bu zayıf stil olarak kabul edilir ve bunun yerine adlandırılmış işlevlerle özyineleme önerilir. Fonksiyonları argüman olarak açıkça iletme yoluyla anonim özyineleme, işlevleri argüman olarak destekleyen herhangi bir dilde mümkündür, ancak bu, adıyla açıkça yinelemeye göre daha uzun ve daha az net olduğu için pratikte nadiren kullanılır.

Teorik bilgisayar biliminde, isimsiz özyineleme önemlidir, çünkü isimlendirilmiş fonksiyonlar gerektirmeden özyinelemenin uygulanabileceğini gösterir. Bu, özellikle lambda hesabı, anonim tek işlevli, ancak herhangi bir özyinelemeli işlevi hesaplayabilen. Bu anonim özyineleme, genel olarak şu yolla üretilebilir: sabit nokta birleştiriciler.

Kullanım

Anonim özyineleme, öncelikle anonim işlevler özellikle oluştuklarında kapanışlar veya olarak kullanılır geri aramalar zorunda kalmamak için adı bağla işlevin.

Anonim özyineleme, öncelikle "geçerli işlevi" çağırmaktan oluşur, bu da doğrudan özyineleme. Anonim dolaylı özyineleme örneğin "arayanı (önceki işlev)" aramak veya daha nadiren daha yukarı çıkmak gibi çağrı yığını ve bu üretmek için zincirlenebilir karşılıklı özyineleme. öz referans "mevcut işlev" in işlevsel bir eşdeğeridir "bu "anahtar kelime nesne yönelimli programlama, birinin mevcut bağlama başvurmasına izin verir.

Anonim özyineleme, adlandırılmış işlevler için de kullanılabilir, bunları adla çağırmak yerine, birinin geçerli işlevde yinelendiğini belirtmek veya kişinin kendisini çağırdığı adı değiştirmeye gerek kalmadan işlevi yeniden adlandırmasına izin vermek için kullanılabilir. Ancak, meselesi olarak programlama stili bu genellikle yapılmaz.

Alternatifler

Adlandırılmış işlevler

Genel alternatif, adlandırılmış işlevleri ve adlandırılmış özyinelemeyi kullanmaktır. Anonim bir işlev verildiğinde, bu, JavaScript'teki adlandırılmış işlev ifadelerinde olduğu gibi işleve bir ad bağlayarak veya işlevi bir değişkene atayarak ve ardından JavaScript'teki işlev ifadelerinde olduğu gibi değişkeni çağırarak yapılabilir. Anonim işlevlere izin veren diller genellikle bu işlevlerin değişkenlere atanmasına izin verdiğinden (birinci sınıf işlevler değilse), birçok dil işlevin kendisine başvurmak için bir yol sağlamaz ve anonim özyinelemeyi açıkça reddeder; örnekler şunları içerir Git.[1]

Örneğin, JavaScript'te faktöriyel işlev şu şekilde anonim özyineleme yoluyla tanımlanabilir:[2]

[1, 2, 3, 4, 5].harita(işlevi(n) {     dönüş (!(n > 1)) ? 1 : argümanlar.Aranan(n-1) * n;});

Adlandırılmış bir işlev ifadesi kullanmak için yeniden yazıldı:

[1, 2, 3, 4, 5].harita(işlevi faktöryel(n) {     dönüş (!(n > 1)) ? 1 : faktöryel(n-1) * n;});

İşlevleri bağımsız değişken olarak aktarma

Geçerli işleve başvuran veya işlevi çağıran mekanizmalar olmasa bile, işlevlere bağımsız değişken olarak izin veren bir dilde anonim özyineleme mümkündür. Bu, temel özyinelemeli işleve başka bir parametre ekleyerek ve bu parametreyi özyinelemeli çağrı işlevi olarak kullanarak yapılır. Bu, daha yüksek dereceli bir işlev oluşturur ve bu daha yüksek işlevi geçirir kendisi gerçek özyinelemeli işlev içinde anonim özyinelemeye izin verir. Bu tamamen anonim olarak yapılabilir. sabit nokta birleştirici bu üst düzey işleve. Bu esas olarak akademik ilgi, özellikle de lambda hesabının yinelemeye sahip olduğunu göstermek için, çünkü ortaya çıkan ifade orijinal adlandırılmış özyinelemeli işlevden önemli ölçüde daha karmaşıktır. Tersine, sabit uçlu birleştiricilerin kullanımına genel olarak "anonim özyineleme" denebilir, çünkü bu, başka uygulamalara sahip olmalarına rağmen bunların dikkate değer bir kullanımıdır.[3][4]

Bu, aşağıda Python kullanılarak gösterilmektedir. İlk olarak, bir standart adlı özyineleme:

def gerçek(n):    Eğer n == 0:        dönüş 1    dönüş n * gerçek(n - 1)

Üst düzey bir işlev kullanmak, böylece üst düzey işlev bir bağımsız değişken üzerinde anonim olarak yinelenir, ancak yine de bir bağımsız değişken olarak standart özyinelemeli işleve ihtiyaç duyar:

def fact0(n0):    Eğer n0 == 0:        dönüş 1    dönüş n0 * fact0(n0 - 1)fact1 = lambda f, n1: 1 Eğer n1 == 0 Başka n1 * f(n1 - 1)gerçek = lambda n: fact1(fact0, n)

Standart özyinelemeli işlevi, işlev argümanını çağrıya ileterek ortadan kaldırabiliriz:

fact1 = lambda f, n1: 1 Eğer n1 == 0 Başka n1 * f(f, n1 - 1)gerçek = lambda n: fact1(fact1, n)

İkinci satır, genel bir üst düzey işlev deniliyor birleştirici:

F = lambda f: (lambda x: f(f, x))fact1 = lambda f, n1: 1 Eğer n1 == 0 Başka n1 * f(f, n1 - 1)gerçek = F(fact1)

Anonim olarak yazılmış:[5]

(lambda f: (lambda x: f(f, x))) \(lambda g, n1: 1 Eğer n1 == 0 Başka n1 * g(g, n1 - 1))

İçinde lambda hesabı, yalnızca tek bir değişkenin işlevlerini kullanan, bu, Y birleştirici. İlk olarak, iki değişkenin yüksek dereceli fonksiyonunu, doğrudan bir fonksiyon döndüren tek bir değişkenin fonksiyonu yapın. köri:

fact1 = lambda f: (lambda n1: 1 Eğer n1 == 0 Başka n1 * f(f)(n1 - 1))gerçek = fact1(fact1)

Burada iki "kendisine daha yüksek dereceden bir işlev uygulama" işlemi vardır: f (f) ilk satırda ve fact1 (fact1) saniyede. İkinci çift başvuruyu bir birleştirici verim:

C = lambda x: x(x)fact1 = lambda f: (lambda n1: 1 Eğer n1 == 0 Başka n1 * f(f)(n1 - 1))gerçek = C(fact1)

Diğer çift uygulama getirilerini hesaba katmak:

C = lambda x: x(x)D = lambda f: (lambda x: f(lambda v: x(x)(v)))fact1 = lambda g: (lambda n1: 1 Eğer n1 == 0 Başka n1 * g(n1 - 1))gerçek = C(D(fact1))

İki birleştiricinin tek bir kombinasyonda birleştirilmesi, Y birleştirici:

C = lambda x: x(x)D = lambda f: (lambda x: f(lambda v: x(x)(v)))Y = lambda y: C(D(y))fact1 = lambda g: (lambda n1: 1 Eğer n1 == 0 Başka n1 * g(n1 - 1))gerçek = Y(fact1)

Y birleştiricisini genişletmek şunları sağlar:

Y = lambda f: (lambda x: f(lambda v: x(x)(v))) \              (lambda x: f(lambda v: x(x)(v)))fact1 = lambda g: (lambda n1: 1 Eğer n1 == 0 Başka n1 * g(n1 - 1))gerçek = Y(fact1)

Bunları birleştirmek, lambda analizinde faktöriyelin özyinelemeli bir tanımını verir (tek bir değişkenin anonim fonksiyonları):[6]

(lambda f: (lambda x: f(lambda v: x(x)(v)))           (lambda x: f(lambda v: x(x)(v)))) \(lambda g: (lambda n1: 1 Eğer n1 == 0 Başka n1 * g(n1 - 1)))

Örnekler

APL

İçinde APL, akım dfn üzerinden erişilebilir . Bu, faktöriyelin bu uygulamasında olduğu gibi anonim özyinelemeye izin verir:

   {0=⍵:1  × -1} 5120   {0=⍵:1  × -1}¨ 10    ⍝ 0 ile 9 arasındaki her bir öğeye uygulanır1 1 2 6 24 120 720 5040 40320 362880

JavaScript

İçinde JavaScript, mevcut işleve şu yolla erişilebilir: arguments.calleearama işlevine şu yolla erişilebilir: arguments.caller. Bunlar, faktöriyelin bu uygulamasında olduğu gibi anonim özyinelemeye izin verir:[2]

[1, 2, 3, 4, 5].harita(işlevi(n) {    dönüş (!(n > 1)) ? 1 : argümanlar.Aranan(n - 1) * n;});

Perl

İle başlayan Perl 5.16, mevcut alt programa şu yolla erişilebilir: __ALT__ geçerli alt yordama bir başvuru döndüren belirteç veya undef bir alt programın dışında.[7] Bu, faktöriyelin aşağıdaki uygulamasında olduğu gibi anonim özyinelemeye izin verir:

#! / usr / bin / perlkullanım özellik ":5.16";Yazdır alt {    benim $ x = vardiya;    $ x > 0    ? $ x * __ALT__->( $ x - 1 )    : 1;}->(5), " n";

R

İçinde R, mevcut işlev kullanılarak çağrılabilir Hatırlama. Örneğin,

saf(0:5, işlevi(n) {  Eğer (n == 0) dönüş(1)  n * Hatırlama(n - 1)})

Bununla birlikte, başka bir işleve argüman olarak aktarılırsa çalışmaz, ör. lapply, anonim işlev tanımının içinde. Bu durumda, sys.function (0) kullanılabilir.[8] Örneğin, aşağıdaki kod bir listeyi yinelemeli olarak kareler:

(işlevi(x) {  Eğer (is.list(x)) {    lapply(x, sys.function(0))  } Başka {    x ^ 2  }})(liste(liste(1, 2, 3), liste(4, 5)))

Referanslar

  1. ^ Sorun 226: Anonim bir işlevi Go'da geçici çözümler olmadan yinelemek imkansızdır.
  2. ^ a b Cevap Yazan olliej, Ekim 25 '08 to "Arguments.callee.caller özelliği neden JavaScript'te kullanımdan kaldırıldı? ", StackOverflow
  3. ^ Bu terminoloji büyük ölçüde folklor, ancak şu şekilde görünür:
    • Trey Nash, Hızlandırılmış C # 2008, Apress, 2007, ISBN  1-59059-873-3, s. 462-463. Büyük ölçüde türetilmiştir Wes Dyer adlı kullanıcının blogu (sonraki maddeye bakın).
    • Wes Dyer C # 'ta Anonim Özyineleme, 02 Şubat 2007, yukarıdaki kitapta bulunan büyük ölçüde benzer bir örnek içeriyor, ancak daha fazla tartışma eşlik ediyor.
  4. ^ If Works Y birleştiricisinin türetilmesi, 10 Ocak 2008
  5. ^ Hugo Walter cevabı to "Bir lambda işlevi Python'da kendini yinelemeli olarak çağırabilir mi? "
  6. ^ Nux'un cevabı to "Bir lambda işlevi Python'da kendini yinelemeli olarak çağırabilir mi? "
  7. ^ Perldoc, "'Current_sub' özelliği ", perldoc özelliği
  8. ^ agstudy'nin cevabı -e Anonim özyinelemeli işlev yazmak için şu anda çağrılan işlevi alın -de StackOverflow