Bir süre döngüsü özünde bir özyineleme midir?


37

Bir süre döngü özünde bir özyineleme olup olmadığını merak ettim?

Sanırım, bir süre döngüsü sonunda kendisini çağıran bir işlev olarak görülebilir. Özyineleme değilse, fark nedir?



13
Özyinelemeyi yinelemeye dönüştürebilir ve tam tersi, evet. Bu aynı oldukları anlamına gelmez, aynı yeteneklere sahipler. Özyinelemenin daha doğal olduğu zamanlar vardır ve yinelemenin daha doğal olduğu zamanlar vardır.
Polygnome

18
@MooingDuck İndüksiyonla herhangi bir özyinelemenin yineleme veya tam tersi olarak yazılabileceğini kanıtlayabilirsiniz. Evet, çok farklı görünecek, ancak yine de yapabilirsiniz.
Polygnome

6
Burada özünde aynı olan ne anlama geliyor? Programlamada özyinelemenin kullanılması, yinelemeden (döngüler) farklı olan belirli bir şey anlamına gelir. CS'de, şeylerin teorik matematik tarafına yaklaştığınızda, bu şeyler biraz farklı şeyler ifade etmeye başlar.
hyde

3
@MooingDuck Özyinelemeli yinelemeli dönüşüm aslında oldukça önemsiz. İşlev çağrıları için bir işlev çağrısı parametresi ve sonuç yığını tutmanız yeterlidir. Özyinelemeli aramaları parametreleri arama yığına ekleyerek değiştirirsiniz. eminim algoritmanın yapısını biraz kıran yığının tüm işlemleri vardır, ancak bir kez bunu anladığınızda kodun aynı şeyi yaptığını görmek oldukça kolaydır. Temel olarak, özyinelemeli tanımlarında belirtilen çağrı yığınını açıkça yazıyorsunuz.
Bakuriu

Yanıtlar:


116

Döngüler çok fazla özyineleme değildir . Aslında, bunlar zıt mekanizmanın ana örneğidir : yineleme .

Yineleme noktası işlem bir eleman olmasıdır aramaları başka bir örneği. Döngü kontrol makineleri sadece atlar , başladığı noktaya geri.

Kodda dolaşmak ve başka bir kod bloğunu çağırmak farklı işlemlerdir. Örneğin, döngünün başlangıcına atladığınızda, döngü kontrol değişkeni hala atlamadan önceki değere sahiptir. Ancak, içinde bulunduğunuz rutinin başka bir örneğini çağırırsanız, yeni örneğin tüm değişkenlerinin yeni, ilgisiz kopyaları vardır. Etkili olarak, bir değişken birinci işlem seviyesinde bir değere ve daha düşük bir seviyede bir değere sahip olabilir.

Bu özellik, birçok özyinelemeli algoritmaların çalışması için çok önemlidir ve bu nedenle, tüm bu değerleri izleyen bir çerçeve dizisini yönetmeden yinelemeyle özyinelemeyi taklit edemezsiniz.


10
@Giorgio Bu doğru olabilir, ancak cevabın yapmadığı iddiası üzerine bir yorum. Bu cevapta "keyfi olarak" bulunmaz ve anlamını önemli ölçüde değiştirir.
hvd

12
@ hvd Prensipte, kuyruk özyineleme, diğerleri gibi tam özyinelemedir. Akıllı derleyiciler, gerçek "yeni bir yığın çerçevesi oluşturma" bölümünü optimize edebilir, böylece oluşturulan kod bir döngüye çok benzerdir, ancak bahsettiğimiz kavramlar kaynak kod seviyesine uygulanır. Bir algoritmanın kaynak kodunu önemli olan bir form olduğunu düşünüyorum , bu yüzden hala özyineleme derim
Kilian Foth

15
@Giorgio "bu tam olarak özyinelemenin yaptığı şeydir: kendisini yeni argümanlarla çağırın" - çağrı hariç. Ve argümanlar.
hobbs

12
@Giorgio Burada çoğu kelimeden farklı kelimelerin tanımlarını kullanıyorsunuz. Kelimeler, bilirsin, iletişimin temelidir. Bu Programcılar, CS Yığın Değişimi değil. Önerdiğiniz gibi "argüman", "çağrı", "işlev" gibi kelimeler kullanırsak, gerçek kod hakkında tartışmak imkansız olur.
hyde

6
@Giorgio Soyut konsepte bakıyorum. Yinelendiğin ve döndüğün kavram var. Onlar farklı kavramlar. Hobbs,% 100 argüman olmadığı ve çağrı olmadığı için doğrudur. Temelde ve soyut olarak farklılar. Ve bu iyi çünkü farklı problemleri çözüyorlar. Öte yandan, tek aracınız özyineliyken döngüleri nasıl uygulayabileceğinize bakıyorsunuz. Hobilere, uygulama hakkında düşünmeyi bırakmasını ve metodolojinizin gerçekten yeniden değerlendirilmeye ihtiyacı olan şey olduğunda kavramlara bakmaya başlamasını söylüyorsunuz.
corsiKa

37

X'in özünde Y olduğunu söylemek, yalnızca X'i ifade ettiğinizi aklınızda bulunduran (biçimsel) bir sisteminiz varsa mantıklı gelir. whileLambda hesabı açısından anlamını tanımlarsanız, özyinelemeden * bahsedebilirsiniz *; Eğer bunu bir kayıt makinesi olarak tanımlarsanız, muhtemelen kullanmayacaksınız.

Her iki durumda da, sadece bir süre döngüsü içerdiğinden özyinelemeli bir işlev çağırırsanız, insanlar muhtemelen sizi anlamaz.

* Belki de yalnızca dolaylı olarak, örneğin bunu tanımlarsanız fold.


4
Adil olmak gerekirse, işlev herhangi bir tanımda özyinelemeli değildir. Sadece özyinelemeli bir öğe olan döngü içerir.
Luaan

@Luaan: Kesinlikle öyle, ancak whileyapı özyinelemeli dillerde genellikle işlevlerin bir özelliği olduğundan, bu bağlamda "özyinelemeli" olarak tanımlayabilecek başka bir şey düşünemiyorum.
Anton Golov

36

Bu senin bakış açına bağlı.

Hesaplanabilirlik teorisine bakarsanız, yineleme ve özyineleme aynı derecede ifade edicidir . Bunun anlamı, bir şeyi hesaplayan bir fonksiyon yazabilmenizdir ve özyinelemeli veya yinelemeli olarak yapıp yapmamanız önemli değildir, her iki yaklaşımı da seçebileceksiniz. Yinelemeli olarak hesaplayamadığınız, yinelemeli olarak hesaplayamadığınız ve tersi şekilde hesaplayabileceğiniz hiçbir şey yoktur (her ne kadar programın dahili çalışmaları farklı olabilir).

Pek çok programlama dili, özyinelemeyi ve yinelemeyi aynı şekilde ve iyi bir sebepten dolayı işlemez. Genellikle , özyineleme, dilin / derleyicinin çağrı yığınını yönettiği ve yinelemenin kendiniz için yığın işleme yapmanız gerekebileceği anlamına gelir.

Ancak, dil vardır , özellikle fonksiyonel diller - - döngüler gibi şeyler (için, süre) olduğu aslında sadece sözdizimsel yineleme için şeker ve sahne arkasında hayata bu şekilde. Bu genellikle işlevsel dillerde istenir, çünkü genellikle döngü kavramı yoktur ve ekleri pratik değil, hesaplamaları daha karmaşık hale getirir.

Yani hayır, onlar aslında aynı değildir . Bunlar eşit derecede ifade edicidir , yani yinelemeli olarak bir şeyi hesaplayamazsınız, özyinelemeli olarak hesaplayamazsınız ve bunun tersi de geçerlidir, ancak bu genel davada (Kilise-Turing tezi uyarınca) bununla ilgilidir.

Burada tekrarlı programlar hakkında konuştuğumuzu unutmayın . Veri yapılarında (örneğin, ağaçlar) başka özyinelemeler de vardır.


Bir uygulama bakış açısıyla bakarsanız, özyineleme ve yineleme aynı değildir. Özyineleme, her çağrı için yeni bir yığın çerçeve oluşturur. Özyinelemenin her adımı kendi kendine yeten, hesaplama için argümandan (kendiliğinden) argümanlar alıyor.

Diğer taraftan döngüler çağrı çerçeveleri oluşturmaz. Onlar için bağlam her adımda korunmaz. Döngü için program, döngü koşulu başarısız olana kadar sadece döngünün başına geri atlar.

Bunu bilmek oldukça önemlidir, çünkü gerçek dünyada oldukça radikal farklılıklar yaratabilir. Özyineleme için, tüm içerik her çağrıya kaydedilmelidir. Yinelemede, hangi değişkenlerin bellekte olduğunu ve nereye kaydedildiğini kesin olarak kontrol edebilirsiniz.

Bu şekilde bakarsanız, çoğu dilde yinelemenin ve özyinelemenin temelde farklı olduğunu ve farklı özelliklere sahip olduğunu hızlıca görürsünüz. Duruma bağlı olarak, özelliklerden bazıları diğerlerinden daha çok arzu edilir.

Özyineleme, programların test edilmesini ve kanıtlanmasını daha basit ve kolay hale getirebilir . Bir özyinelemenin yinelemeye dönüştürülmesi genellikle kodu daha karmaşık hale getirir ve başarısızlık olasılığını artırır. Öte yandan, yinelemeye dönüştürmek ve çağrı yığını çerçevelerinin miktarını azaltmak, çok fazla ihtiyaç duyulan hafızayı kaydedebilir.


Yerel değişkenler ve özyinelemeli bir dil, ancak hiçbir dizilim, yerel değişkenlere sahip yinelemeli bir dil tarafından gerçekleştirilemeyen ve dizisiz bir görev gerçekleştiremez. Örneğin, bir girişin bilinmeyen uzunlukta bir alfasayısal dize ve ardından boş ve ardından orijinal dizenin karakterlerini ters sırayla içerip içermediğini raporlayın.
supercat,

3
Dil tamamlandığı sürece, yapabilir. Bir dizi, örneğin (iki katına bağlı) bağlantılı bir listeyle kolayca değiştirilebilir. Yineleme veya özyineleme hakkında konuşmak ve eşit olup olmadıkları sadece iki turing-komple dili karşılaştırırsanız anlamlıdır.
Polygnome,

Basit statik veya otomatik değişkenlerden başka bir şey yapmamak, yani Turing-complete olmamak . Tamamen yinelemeli bir dil, basit deterministik sonlu otomatonla gerçekleştirilebilecek görevlerle sınırlı olacaktır; özyinelemeli bir dil, en azından bir itme deterministik sonlu otomatiği gerektiren işleri yapma yeteneği ekleyecektir.
supercat,

1
Eğer dil tam değilse, başlamak için anlamsız. DFA'lar keyfi yineleme veya özyineleme yapamazlar.
Polygnome

2
Hiçbir uygulama aslında Turing tamamlanmadı ve Turing tamamlanmayan diller birçok amaç için yararlı olabilir. Sonlu bir aralığa sahip sonlu sayıda değişkenle çalıştırılabilen herhangi bir program, her olası değer kombinasyonunun ayrı bir durum olduğu bir DFA ile yerleştirilebilir.
supercat,

12

Aradaki fark örtük istif ve semantiktir.

"Sonunda kendisini çağıran" bir döngüde, bittiğinde geri taranacak bir yığın yoktur. Son yineleme, biteceği haliyle ne olacağını belirler.

Bununla birlikte, özyineleme, daha önce yapılan işin durumunu hatırlayan bu örtülü yığın olmadan yapılamaz.

Açıkça bir yığına erişim izni verirseniz yineleme ile ilgili herhangi bir özyineleme problemini çözebileceğiniz doğrudur. Ancak bu şekilde yapmak aynı değildir.

Anlamsal fark, özyinelemeli koda bakmanın yinelemeli koddan tamamen farklı bir şekilde bir fikri ilettiği gerçeğiyle ilgilidir. Yinelemeli kod işleri bir anda bir adım yapar. Önceden gelen herhangi bir durumu kabul eder ve yalnızca bir sonraki durumu oluşturmak için çalışır.

Özyinelemeli kod bir sorunu fraktallara böler. Bu küçük parça o büyük parçaya benziyor, böylece sadece bu kısmını ve bu kısmını da aynı şekilde yapabiliriz. Sorunları düşünmenin farklı bir yolu. Çok güçlü ve alışmak gerekiyor. Birkaç satırda çok şey söylenebilir. Bir yığına erişimi olsa bile, bunu bir süre döngüsünden çıkaramazsınız.


5
Ben "örtülü yığın" yanıltıcı olduğunu düşünüyorum. Özyineleme, bir dilin anlambiliminin bir parçasıdır, bir uygulama detayı değildir. (Verilen özyinelemeyi destekleyen dillerin çoğu , bir çağrı yığını kullanır; ancak ilk olarak, bu tür birkaç dil, ikincil olarak, her özyinelemeli aramanın mutlaka arama yığınına eklenmemesini sağladığı için, her dilde yapılan aramaları mutlaka arama yığınına ekler. olarak kuyruk çağrı eliminasyon .) olağan / basit uygulama anlama soyutlama üzerindeki kolu almak yararlı olabilir, ancak bu bütün hikaye düşünerek kendinizi kandırmak olmamalıdır.
ruakh

2
@ruakh Ben kuyruk çağrısı eliminasyon kullanarak sabit alanda yürüten bir fonksiyon olduğunu tartışırdım gerçekten bir döngü. Burada yığın uygulama detayı değil, farklı tekrarlama seviyeleri için farklı durumlar biriktirmenize izin veren soyutlamadır.
Cimbali

@ruakh: tek bir özyinelemeli çağrı içindeki herhangi bir durum özyineleme derleyici tarafından yinelemeli bir döngüye dönüştürülemediği sürece, kapalı bir yığında depolanır. Kuyruk çağrısı ortadan kaldırması , işlevinizi yeniden özyinelemeli yapmak için yeniden düzenlemek istiyorsanız, farkında olmanız gereken , bir uygulama ayrıntısıdır. Ayrıca, "bu tür birkaç dil yok" - özyinelemeli aramalar için bir yığına ihtiyaç duymayan dillere bir örnek verebilir misiniz?
Groo


@ruakh: CPS kendiliğinden aynı örtük yığını yaratır, bu yüzden anlam ifade etmek için kuyruk çağrısı eliminasyonuna dayanması gerekir (ki bu yapılanma nedeniyle önemsizdir). Bağlandığın wikipedia makalesi bile aynı şeyi söylüyor: CPS'yi kuyruk çağrısı optimizasyonu olmadan kullanmak (TCO), yalnızca yapılanma devam etmenin, özyinelemede potansiyel olarak büyümesine değil, aynı zamanda çağrı yığınına da neden olacaktır .
Groo

7

Hepsi, terimi kendi kullanımınıza bağlıyor . Programlama dili düzeyinde, sözdizimsel ve anlamsal olarak farklılar ve oldukça farklı performans ve bellek kullanımlarına sahipler. Ancak teoriye yeterince derin bir şekilde kazıyorsanız, birbirleriyle tanımlanabilirler ve bu nedenle bazı teorik anlamda "aynıdır".

Asıl soru şudur: İterasyon (döngüler) ile özyineleme arasında ayrım yapmak ne zaman anlamlıdır ve ne zaman aynı şeyleri düşünmek yararlı olur? Bunun cevabı aslında programlamada (matematiksel ispatlar yazarken) yinelemeyle yineleme arasında ayrım yapmanın önemli olduğudur.

Özyineleme, yeni bir yığın çerçeve, yani her çağrı için yeni bir yerel değişken kümesi oluşturur. Bunun ek yükü vardır ve yığın üzerinde yer kaplar, bu da yeterince derin bir özyinelemenin programın çökmesine neden olan yığının üzerine taşabileceği anlamına gelir. Diğer yandan, yineleme yalnızca var olan değişkenleri değiştirir, bu nedenle genellikle daha hızlıdır ve yalnızca sabit miktarda bellek alır. Yani bu bir geliştirici için çok önemli bir ayrımdır!

Kuyruk çağırma özyinelemeli dillerde (tipik olarak işlevsel diller), derleyici özyinelemeli çağrıları yalnızca sabit miktarda bellek alabilecek şekilde optimize edebilir. Bu dillerde, önemli ayrım yineleme ve özyineleme değil, kuyruk çağrısı-özyineleme sürümü kuyruk çağrısı-özyineleme ve yinelemedir.

Alt satır: Farkı söyleyebilmeniz gerekir, aksi takdirde programınız çökecektir.


3

whiledöngüler bir özyineleme şeklidir, bakınız örneğin bu soruya verilen cevaplar . Hesaplanabilirlik teorisindeki operator-operatörüne karşılık gelirler (bakınız, örneğin buraya ).

forBir dizi sayı üzerinde yinelenen tüm döngü çeşitleri, sonlu bir koleksiyon, bir dizi ve benzeri, ilkel özyinelemeye karşılık gelir, bakınız örneğin burada ve burada . O Not forC, C döngüler ++, Java ve benzeri, aslında bir sözdizimsel şeker whiledöngü ve bu nedenle tekabül ilkel özyinelemeye değildir. Pascal fordöngüsü, ilkel özyinelemenin bir örneğidir.

Önemli bir fark, ilkel özyinelemenin daima sona ermesidir; oysa genel özyinelemenin ( whiledöngüler) sona ermeyebilir.

DÜZENLE

Yorumlar ve diğer cevaplarla ilgili bazı açıklamalar. “Bir şey kendisi veya türüyle tanımlandığında özyineleme oluşur.” (bkz. wikipedia ). Yani,

Bir süre döngüsü özünde bir özyineleme midir?

Çünkü bir whiledöngüyü kendisi açısından tanımlayabilirsiniz .

while p do c := if p then (c; while p do c))

o zaman, evet , bir whiledöngü özyinelemenin bir şeklidir. Özyinelemeli işlevler, özyinelemenin bir başka biçimidir (özyinelemeli tanımlamanın başka bir örneği). Listeler ve ağaçlar diğer özyinelemelerdir.

Örtüşen birçok cevap ve yorum tarafından kabul edilen bir başka soru ise;

Döngüler ve özyinelemeli işlevler eşdeğer midir?

Bu sorunun cevabı hayır : Bir whiledöngü, özyinelemeli özyinelemeye karşılık gelir, ancak döngü tarafından erişilen değişkenler örtük özyinelemeli fonksiyonun argümanlarına karşılık gelir; whileFazladan bir yığın kullanmadan bir döngü ile modellenemez .

Bu nedenle, "bir whiledöngü özyinelemenin bir şeklidir" gerçeği "bazı özyinelemeli işlevlerin bir whiledöngü tarafından ifade edilemeyeceği" gerçeğiyle çelişmez .


2
@morbidCode: ilkel özyineleme ve μ-özyineleme, örneğin hesaplanabilirlik teorisinde çalışılan, belirli kısıtlamalara (veya bunların eksikliği) sahip özyineleme biçimleridir. Görünen o ki, sadece bir FORdöngüye sahip bir dil, tüm ilkel özyinelemeli fonksiyonları tam olarak hesaplayabilir ve sadece bir WHILEdöngüye sahip bir dil tam olarak tüm-özyinelemeli fonksiyonları hesaplayabilir (ve--özyinelemeli fonksiyonların tam olarak bu fonksiyonlar olduğu ortaya çıkar) bir Turing Makinesi hesaplayabilir). Veya kısaltmak için: ilkel özyineleme ve µ özyineleme matematik / hesaplanabilirlik teorisinin teknik terimleridir.
Jörg W Mittag

2
"Özyinelemenin" kendisini çağıran bir işlevi ima ettiğini ve mevcut yürütme durumunun yığına itilen vb. bu nedenle çoğu makinenin kaç seviyeyi tekrarlayabileceğiniz konusunda pratik bir sınırı vardır. Döngülerde böyle bir sınır yoktur, çünkü dahili olarak bir "JMP" gibi bir şey kullanırlar ve yığını kullanmazlar. Sadece benim anlayışım yanlış olabilir.
Jay,

13
Bu cevap, “özyinelemeli” sözcüğü için OP'nin kullandığından tamamen farklı bir tanım kullanıyor ve bu nedenle oldukça yanıltıcı.
Mooing Duck

2
@DavidGrinberg: Alıntı: "Döngüler için C, C ++, Java ilkel özyinelemenin bir örneği değildir. İlkel özyinelemenin, döngüye başlamadan önce maksimum yineleme / özyineleme derinliği sayısının sabit olduğu anlamına gelir." Giorgio, Hesaplanabilirlik teorisi ilkellerinden bahsediyor . Programlama dilleriyle ilgisi yoktur.
Mooing Duck

3
Mooing Duck ile aynı fikirdeyim. Hesaplanabilirlik teorisi teorik CS'de ilginç olsa da, herkesin OP'nin programlama dilleri kavramı hakkında konuştuğunu kabul ettiğini düşünüyorum.
Voo

2

Bir kuyruk çağrısı (veya özyinelemeli özyinelemeli çağrı) tam olarak bir "argümanlarla gitme " ( çağrı yığına herhangi bir ek çağrı çerçevesine basmadan) olarak uygulanır ve bazı işlevsel dillerde (özellikle Ocaml) genel döngü yöntemidir.

Bu yüzden bir süre döngüsü (onlara sahip olan dillerde) bir kuyruk çağrısı ile bitmiş olarak görülebilir (veya kafa testi).

Aynı şekilde, sıradan (kuyruk çağrısı) özyinelemeli çağrılar döngülerle simüle edilebilir (bir miktar yığın kullanarak).

Devamlılıklar ve devam eden stil hakkında da okuyun .

Yani "özyineleme" ve "yineleme" derinden eşdeğerdir.


1

Hem yinelemenin hem de sınırsız while-döngülerinin hesaplamalı ifade edilebilirlik açısından eşdeğer olduğu doğrudur. Yani, yinelenerek yazılmış herhangi bir program, bunun yerine döngüler kullanılarak eşdeğer bir programa yeniden yazılabilir ve bunun tersi de geçerlidir. Her iki yaklaşım turing-complete , yani herhangi bir hesaplanabilir fonksiyonu hesaplamak için kullanılabilir.

Programlama açısından temel fark, özyinelemenin çağrı yığında depolanan verileri kullanmanıza izin vermesidir. Bunu göstermek için, bir döngü veya özyineleme kullanarak tek bir bağlantılı listenin öğelerini yazdırmak istediğinizi varsayın. Örnek kod için C kullanacağım:

 typedef struct List List;
 struct List
 {
     List* next;
     int element;
 };

 void print_list_loop(List* l)
 {
     List* it = l;
     while(it != NULL)
     {
          printf("Element: %d\n", it->element);
          it = it->next;
     }
 }

 void print_list_rec(List* l)
 {
      if(l == NULL) return;
      printf("Element: %d\n", l->element);
      print_list_rec(l->next);
 }

Basit değil mi? Şimdi küçük bir değişiklik yapalım: Listeyi ters sırada yazdırın.

Özyinelemeli değişken için bu, orijinal işlev için neredeyse önemsiz bir değişikliktir:

void print_list_reverse_rec(List* l)
{
    if (l == NULL) return;
    print_list_reverse_rec(l->next);
    printf("Element: %d\n", l->element);
}

Yine de döngü işlevi için bir sorunumuz var. Listemiz tek tek bağlantılıdır ve bu nedenle yalnızca ileriye doğru kaydırılabilir. Ancak geriye doğru yazdırdığımız için son elemanı yazdırmaya başlamalıyız. Son elemente ulaştıktan sonra, artık ikinci-son elemente geri dönemeyiz.

Bu yüzden ya bir sürü yeniden gezinme yapmak zorundayız ya da ziyaret edilen unsurları izleyen ve daha sonra verimli bir şekilde yazdırabileceğimiz bir yardımcı veri yapısı oluşturmalıyız.

Neden bu özyineleme ile ilgili bir problemimiz yok? Çünkü özyinelemede zaten yardımcı bir veri yapımız var: İşlev çağrısı yığını.

Özyinelemeli özyinelemeli çağrının önceki çağrısına geri dönmemize izin verdiğinden, tüm yerel değişkenler ve bu çağrının durumu hala bozulmamışken, yinelemeli durumda modellemek için can sıkıcı bir esneklik kazanıyoruz.


1
Tabii ki, ikinci özyinelemeli işlev kuyruk özyinelemeli değildir - yığını yeniden kullanmak için TCO kullanamadığınız için alan için optimize etmek çok daha zordur. İki kat bağlantılı bir liste uygulamak, her iki algoritmayı da her iki şekilde de, her bir işaretçi / referansın alan maliyeti karşılığında önemsiz hale getirir.
Baldrickk

@Baldrickk Tail-recursion ile ilgili komik olan şey, döngü sürümünün nasıl göründüğüne çok daha yakın olan bir sürümün bitmesidir, çünkü tekrar arama yığınında durum kaydetme yeteneğinizi kaldırır. Şüpheli bir şekilde bağlanmış bir liste onu çözecektir, ancak veri yapısını yeniden tasarlamak bu soruna çalışırken genellikle bir seçenek değildir. Buradaki örnek yapay olarak biraz kısıtlı olsa da, özyinelemeli cebirsel türlerin bağlamında işlevsel dillerde sıkça ortaya çıkan bir örüntüyü göstermektedir.
ComicSansMS

Demek istediğim, eğer bu soruna rastlarsanız, onu uygulamak için kullandığınız dilin yapısından daha fazla işlevsel tasarım eksikliğinden kaynaklanıyor ve her seçimin kendi olumlu ve olumsuz
yönleri var

0

Döngüler, belirli bir görevi başarmak için özel bir özyineleme biçimidir (çoğunlukla yineleme). Biri birçok dilde aynı performansla [1] tekrarlanan stilde bir döngü uygulayabilir. ve SICP'de [2], döngülerin "sentastik şeker" olarak tanımlandığını görebilirsiniz. Zorunlu programlama dillerinin çoğunda, bloklar için ve blokları ana fonksiyonlarıyla aynı kapsamı kullanıyor. Bununla birlikte, işlevsel programlama dillerinin çoğunda ne döngüler vardır ne de döngü yoktur çünkü bunlara ihtiyaç yoktur.

Zorunlu dillerin döngüler için / süre olmasının nedeni, durumları mutasyona uğratarak idare etmeleridir. Ama aslında, eğer farklı bir perspektiften bakarsanız, bir süre bloğunu bir fonksiyonun kendisi olarak düşünürseniz, parametre alarak, onu işleme koyar ve yeni bir durum döndürürseniz - bu aynı fonksiyonun farklı parametrelerle çağrılması olabilir - siz Döngüyü özyineleme olarak düşünebilir.

Dünya aynı zamanda değişken veya değişken olarak tanımlanabilir. dünyayı bir kurallar kümesi olarak tanımlarsak, tüm kuralları ve mevcut durumu parametre olarak alan nihai bir işlev çağırırsak ve yeni durumu aynı işlevselliğe sahip bu parametrelere göre döndürürsek (aynı durumda bir sonraki durumu oluşturur) yol), bunun bir özyineleme ve bir döngü olduğunu söyleyebiliriz.

Aşağıdaki örnekte, hayat, fonksiyonun "kurallar" ve "durum" olmak üzere iki parametre almasıdır ve bir dahaki sefere yeni durum oluşturulacaktır.

life rules state = life rules new_state
    where new_state = construct_state_in_time rules state

[1]: kuyruk çağrısı optimizasyonu, işlevsel programlama dillerinde mevcut fonksiyon yığınını yeni bir tanesini oluşturmak yerine özyinelemeli çağrılarda kullanmak için ortak bir optimizasyondur.

[2]: Bilgisayar Programlarının Yapısı ve Yorumlanması, MIT. https://mitpress.mit.edu/books/structure-and-interpretation-computer-programs


4
@Giorgio Olumsuz oyum değil, sadece bir tahmin: Sanırım çoğu programcı hissediyorum, özyinelemenin özyinelemeli bir işlev çağrısı olduğunu ima ediyor, çünkü, özyinelemenin kendisi, çağrılan işlev budur. Bir döngüde özyinelemeli fonksiyon çağrısı yoktur. Dolayısıyla, özyinelemeli işlev çağrısı olmayan bir döngünün özel bir özyineleme biçimi olduğunu söylemek, bu tanımlamaya göre, kesinlikle yanlış olur.
hyde

1
Belki daha soyut bir bakış açısıyla bakmak, farklı şeyler gibi görünen şey aslında kavramsal olarak aynıdır. İnsanların bir şeyi öğrenmek için bir şans olarak değerlendirmek yerine beklentilerine uymadıkları için cevapları zayıfladıklarını düşünmek oldukça cesaret kırıcı ve üzücü buluyorum. Söylemeye çalışan tüm cevaplar: "Hey, bak, bunlar yüzeyde farklı görünüyor, ama aslında daha soyut bir seviyede aynıdır" ifadesi reddedildi.
Giorgio

3
@ George: Bu sitenin amacı soruların cevaplarını almaktır. Yararlı ve doğru cevaplar en çok oyu hak eder, kafa karıştırıcı ve yararsız olan cevaplar çok daha fazla hak eder. Hangi farklı tanımın kullanıldığını açıkça belirtmeden , ortak bir terimin farklı bir tanımını kullanan bir cevap , kafa karıştırıcı ve yararsızdır. Eğer cevabı zaten biliyorsan, tabiri caizse, faydalı olmayan cevaplar sadece yazarlara terminolojiyi daha iyi kavradıklarını göstermeye yarar.
JacquesB

2
@JacquesB: "Sadece cevabı zaten biliyorsan, konuşması çok yardımcı olsaydı anlamlıdır ...": Bu, aynı zamanda sadece okuyucunun bildiklerini veya ne düşündüğünü onayladığını doğrulayan cevaplardan da söz edilebilir. Eğer bir cevap açık olmayan bir terminoloji getiriyorsa, indirmeden önce daha fazla ayrıntı istemek için yorum yazmak mümkündür.
Giorgio

4
Döngüler özel bir özyineleme şekli değildir . Hesaplanabilirlik teorisine ve örneğin teorik WHILE dili ve µ-matematiğine bakın. Evet, bazı diller için sözdizimsel şeker gibi döngüler kullanmak aslında perde arkasında özyinelemeye kullanmak, ancak tekrarlama ve yineleme çünkü bunu yapabilir eşit etkileyici , aynı değildir çünkü.
Polygnome

-1

Bir süre döngü özyinelemeden farklı.

Bir işlev çağrıldığında, aşağıdakiler gerçekleşir:

  1. Bir yığın çerçeve yığına eklenir.

  2. Kod işaretçisi, fonksiyonun başlangıcına hareket eder.

Bir süre döngüsü sonunda olduğunda aşağıdakiler gerçekleşir:

  1. Bir durum bir şeyin doğru olup olmadığını sorar.

  2. Eğer öyleyse, kod bir noktaya atlar.

Genel olarak while döngüsü aşağıdaki sözde koda benzer:

 if (x)

 {

      Jump_to(y);

 }

Hepsinden önemlisi, özyineleme ve döngüler farklı montaj kodu gösterimlerine ve makine kodu gösterimlerine sahiptir. Bu, aynı olmadığı anlamına gelir. Aynı sonuçlara sahip olabilirler, ancak farklı makine kodu aynı şeyin% 100 olmadığını kanıtlıyor.


2
Bir prosedür çağrısının ve bir süre döngüsünün uygulanmasından bahsediyorsunuz ve farklı bir şekilde uygulandıklarından, farklı oldukları sonucuna varıyorsunuz. Ancak, kavramsal olarak çok benzer.
Giorgio

1
Derleyiciye bağlı olarak, en iyi duruma getirilmiş, sıralı bir özyineleme çağrısı düz düzlem olarak aynı düzeneği üretebilir.
hyde

@hit ... ki bu sadece birinin ötekiyle ifade edilebildiği bilinen gerçeğine bir örnek; aynı oldukları anlamına gelmez. Biraz kütle ve enerji gibi. Elbette, aynı çıktıyı üretmenin tüm yollarının "aynı" olduğu söylenebilir. Eğer dünya sınırlı olsaydı, sonunda bütün programlar karmaşık olacaktı.
Peter - Monica'yı yeniden

@Giorgio Nah, bu bir uygulama değil, mantıklı bir açıklamadır. İki şeyin eşdeğer olduğunu biliyoruz ; fakat denklik özdeşlik değildir , çünkü soru (ve cevaplar) tam olarak sonuca nasıl ulaştığımızdır, yani mutlaka algoritmik tanımlamalar (yığın ve değişken vb. ile ifade edilebilir) içerirler.
Peter - Monica

1
@ PeterA.Schneider Evet, ancak bu cevap "doğru değil, hepsinden önemlisi ... farklı montaj kodunu" belirtir.
hyde

-1

Sadece yineleme, özyinelemeye genellikle eşdeğer olmak için yeterli değildir, ancak yığınla yineleme genellikle aynıdır. Herhangi bir özyinelemeli işlev, bir yığınla yinelemeli bir döngü olarak yeniden programlanabilir ve bunun tersi de geçerlidir. Bu, bunun pratik olduğu anlamına gelmez ve herhangi bir durumda, bir veya diğer formun, diğer versiyona göre belirgin faydaları olabileceği anlamına gelmez.

Bunun neden tartışmalı olduğundan emin değilim. Bir yığınla özyineleme ve yineleme aynı işlemsel süreçtir. Tabii ki, aynı "fenomen" dir.

Aklıma gelen tek şey, bunlara "programlama araçları" olarak bakarken, onları aynı şey olarak düşünmemeniz gerektiği konusunda hemfikir olacağım. Bunlar "matematiksel" veya "hesaplamalı" eşdeğerdir (yine bir yığınla yineleme, genel olarak yineleme değil), ancak bu, ikisinin de yapacağı düşüncesiyle sorunlara yaklaşmanız gerektiği anlamına gelmez. Bir uygulama / problem çözme bakış açısına göre, bazı problemler bir şekilde veya diğerinden daha iyi çalışabilir ve bir programcı olarak sizin hangisinin daha uygun olduğuna karar vermektir.

Açıklığa kavuşturmak için, sorunun cevabını bir süre döngü özünde bir özyineleme midir? kesin bir hayır veya en azından "yığınınız yoksa."

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.