Özyinelemeyi kaldırma - perde arkasındaki teoriye bir bakış


10

Bu sitede yeniyim ve bu soru kesinlikle araştırma seviyesi değil - ama iyi. Yazılım mühendisliğinde biraz arka planım var ve CSTheory'de neredeyse hiç yok, ama çekici buluyorum. Uzun bir hikaye kısaca anlatmak gerekirse, bu soru bu sitede kabul edilebilirse aşağıdakilere daha ayrıntılı bir cevap istiyorum.

Yani, her özyinelemeli programın yinelemeli bir analogu olduğunu biliyorum ve "sistem yığını" na benzer bir şey koruyarak ve dönüş adresi vb. Gibi ortam ayarlarını zorlayarak bunun için sunulan popüler açıklamayı anlıyorum. .

Biraz daha somut olmak, (resmi olarak) işlevini çağıran durumlarda bu ifadeyi nasıl kanıtladığını görmek . Ayrıca, bir bazı çağrı yapmasına neden olabilecek bazı koşullu ifadeler varsa ne olur ? Yani, potansiyel fonksiyon çağrısı grafiğinde kuvvetle bağlı bazı bileşenler bulunur.F i F jF0F1FiFi+1FnF0FiFj

Bu durumların nasıl tekrarlanabileceğini bilmek istiyorum, yinelemeli dönüştürücüye özyinelemeliyiz. Daha önce bahsettiğim el yıkama açıklaması bu sorun için gerçekten yeterli mi? Yani neden bazı durumlarda özyinelemeyi kaldırmayı kolay buluyorum. Özellikle, bir İkili ağacın ön sipariş geçişinden özyinelemeyi kaldırmak gerçekten kolaydır - bu standart bir röportaj sorudur, ancak post order durumunda özyinelemeyi kaldırmak benim için her zaman bir kabus olmuştur.

Gerçekten sorduğum şey 2 soru

(1) Özyinelemenin yinelemeye dönüştürülebileceğine dair daha resmi (ikna edici?) Bir kanıt var mı?

(2) Bu teori gerçekten dışarıdaysa, neden ön siparişi yinelemeyi daha kolay ve postorder'ı bu kadar zor buluyorum ? (sınırlı zekam dışında)


1
yineleme kelimesi gibi :)
Akash Kumar

i tam olarak anlamak eğer emin değilim, ama özyinleme bir yerde biterse o zaman aslında kendi yığını kullanarak bir sistem yığını simüle edebilirsiniz. Bölüm (2) için, problemler hesaplama karmaşıklığı açısından farklı değildir.
singhsumit

Bu sorunun henüz yayınlanmamış olan Bilgisayar Bilimi sitesi için en uygun olacağını düşünüyorum . İkinci sorunuza gelince, bunun neden daha zor olduğunu düşündüğünüzü açıklayabilir misiniz? İşlem neredeyse aynı olmalıdır.
Raphael

yorumlarınız için herkese teşekkürler - sanırım yapacak çok okuma var.
Itachi Uchiha

@Raphael - Neden yineleyici postorder zor olduğunu düşünüyorum (yanı sıra bunu yapamıyorum). Özyinelemeyi kaldırma ile ilgili birkaç makale okuyordum ve kuyruk özyinelemeli fonksiyonlar olarak adlandırılan bir şeyle karşılaştım. Tekrarlamak daha kolay olduğu ortaya çıkıyor. Bunun neden doğru olduğunu hala resmi olarak anlamıyorum; ama eklemem gereken başka bir şey daha var. Yineleyici postorder bir değil iki yığın gerektirir duydum ama ayrıntıları bilmiyorum. Ve şimdi kayboldum - neden bu iki geçiş modu arasındaki bu fark? Ve kuyruk özyinelemesinin kullanımı neden kolaydır?
Itachi Uchiha

Yanıtlar:


6

Doğru anlarsam, başka işlev çağrısı içermeyen işlevleri kendilerine dönüştürme konusunda açıksınızdır.

Öyleyse bir "çağrı zincirimiz" . Ayrıca, kendilerinin özyinelemediğini varsayarsak (onları zaten dönüştürdüğümüz için), tüm bu çağrıları , zaten ele alabileceğimiz doğrudan özyinelemeli bir işlev haline gelen tanımına satır içine alabiliriz.F 1 , , F nFF1FnFF1,,FnF

Bazı kendisinin, FFjF meydana geldiği , yani . Bu durumda, kurtulmak için başka bir numara gerektiren karşılıklı özyineleme var . Fikir, her iki işlevi aynı anda hesaplamaktır. Örneğin, önemsiz durumda:FjFFj

f(0) = a
f(n) = f'(g(n-1))

g(0) = b
g(n) = g'(f(n-1))

ile f've g'yinelemeli olmayan fonksiyonlar (ya da en azından bağımsız fve g) olur

h(0) = (a,b)
h(n) = let (f,g) = h(n-1) in (f'(g), g'(f)) end

f(n) = let (f, _) = h(n) in f end
g(n) = let (_, g) = h(n) in g end

Bu doğal olarak daha fazla işleve ve daha karmaşık işlevlere kadar uzanır.


Yardımcı olduğuma sevindim. Lütfen yanındaki onay işaretini tıklayarak favori yanıtınızı kabul etmeyi unutmayın.
Raphael

1
Raphel, hile sadece her iki özyinelemeli işlev aynı türden bağımsız değişkenleri kabul ettiğinde çalışır. Farklı türde türleri kabul fedip gkabul ediyorsanız , daha genel bir numara gerekir.
Andrej Bauer

@AndrejBauer iyi gözlem, bunu tamamen özledim. raphael'ın yaklaşımını gerçekten sevdim, ama genel durumlarda gözlemlediğiniz gibi, muhtemelen farklı bir fikre ihtiyacımız var. Başka öneri yapabilir misiniz?
Itachi Uchiha

fgn1n2

Bunu nasıl yapacağım konusundaki cevabımı görün.
Andrej Bauer

8

Evet, özyinelemenin yinelemeye dönüştürülebileceğine inanmak için ikna edici nedenler var. Her derleyici kaynak kodunu makine diline çevirdiğinde bunu yapar. Teori için Dave Clarke'ın önerilerini takip etmelisiniz. Özyinelemeyi özyinelemeli olmayan koda dönüştüren gerçek kodu görmek istiyorsanız, PL Hayvanatmachine.ml Bahçemdeki MiniML dilinde bir göz atın ( aslında kodu çalıştıran alt kısımdaki işlevin kuyruk özyinelemeli olduğuna dikkat edin ve böylece önemsiz bir şekilde gerçek bir döngüye dönüştürülebilir).loop

Bir şey daha. MiniML, karşılıklı olarak yinelenen işlevleri desteklemez. Ama bu bir sorun değil. İşlevler arasında karşılıklı özyinelemeniz varsa

f1:A1B1
f2:A2B2
fn:AnBn

özyineleme tek bir özyinelemeli harita olarak ifade edilebilir

f:A1++AnB1++Bn,

8

SECD makinesine bakmak isteyebilirsiniz . İşlevsel bir dil (herhangi bir dil olsa da), yığınların argümanlarını koymak, yeni işlevler "çağırmak" ve bunun gibi basit bir döngü tarafından yönetilen şeyleri yöneten bir dizi talimata çevrilir.
Yinelemeli çağrılar hiçbir zaman gerçekte çağrılmaz. Bunun yerine, çağrılan işlevin gövdesinin talimatları çalıştırılacak yığına yerleştirilir.

İlgili bir yaklaşım CEK makinesidir .

Bunların ikisi de uzun zamandır var, bu yüzden orada çok fazla çalışma var. Ve elbette çalıştıklarına dair kanıtlar var ve bir programı SECD komutlarına "derleme" prosedürü, programın boyutunda doğrusaldır (program hakkında düşünmek zorunda değildir).

Cevabım, istediğini yapmak için otomatik bir prosedür olması. Ne yazık ki, dönüşüm mutlaka bir programcının yorumlaması hemen kolay şeyler açısından olmayacaktır. Bence bir programı yinelemek istediğinizde, programın yinelemeli bir işlev çağrısından döndüğünüzde programın yapması gerekenleri depolamanız gerekir (buna devam denir). Bazı işlevler için (kuyruk özyinelemeli işlevler gibi) devam önemsizdir. Diğerleri için, özellikle de kendiniz kodlamanız gerekiyorsa, devam çok karmaşık olabilir.


Burada dürüst olacağım. Her özyinelemeli programı neden (ve nasıl) yineleyebileceğinizi gerçekten anlamak istiyorum. Ama bir makaleyi okumakta zorlanıyorum - genellikle benim için erişilebilir değiller. yani soruda bahsettiğim "handwavy" açıklamasından daha derin bir sebep istiyorum. ama aynı zamanda bana yeni bir fikir veren bir şeyden de memnunum - nitrit cesur ayrıntılarında tüm kanıtın olması gerekmiyor
Itachi Uchiha

[cntd] Demek istediğim, eğer bir program varsa, neden bir programı diğerinden daha kolay yinelediğimi söylemek için kanıtı beğeneceğim. Ancak bir anlamda, yinelemeli dönüştürücünün özyinelemesi, girdi olarak hangi özyinelemeli program olursa olsun çalışmalıdır. Nt emin, ama böyle bir dönüştürücü yapma durma sorunu kadar zor olabilir sanırım? Ben sadece burada tahmin ediyorum - ama yinelemeli dönüştürücünün varlığını yinelemeyi isterdim ve eğer yaparsa, farklı özyinelemeli programları yinelemenin doğal karmaşıklığını açıklamak isterim. emin değilim, ama soruyu düzenlemeliyim? Sorum açık mı?
Itachi Uchiha

@ItachiUchiha - Sorununuzun kararsız olduğunu düşünmüyorum. Andrej Bauer'ın cevabına bakın. Her derleyicinin kaynak kodunu makine diline çevirdiğinde bunu yaptığını not eder. Ayrıca, MiniM (a) l dilinde özyinelemeyi özyinelemesiz hale dönüştüren gerçek kodu görebileceğinizi ekler. Bu, özyinelemeyi "yinelemek" için bir karar prosedürü olduğunu açıkça göstermektedir. Özyinelemeyi kaldırmanın doğasında (kavramsal) zorluk / karmaşıklıktan emin değilim. Bu soruyu çok net anlamıyorum ama ilginç görünüyor. Belki daha iyi yanıt almak için sorunuzu düzenleyebilirsiniz
Akash Kumar

Cevabım, istediğini yapmak için otomatik bir prosedür olması. Ne yazık ki, dönüşüm mutlaka bir programcının yorumlaması hemen kolay şeyler açısından olmayacaktır. Bence bir programı yinelemek istediğinizde, programın yinelemeli bir işlev çağrısından döndüğünüzde programın yapması gereken şeyleri depolamanız gerekir (buna devam denir). Bazı işlevler için (kuyruk özyinelemeli işlevler gibi) devam önemsizdir. Diğerleri için, özellikle de kendiniz kodlamanız gerekiyorsa, devam çok karmaşık olabilir.
Dave Clarke

6

S : "Özyinelemenin yinelemeye dönüştürülebileceğine dair daha resmi (ikna edici?) Bir kanıt var mı?"

C : Bir Turing Makinesinin Turing bütünlüğü :-)

Şakalar yapıyor, Turing eşdeğeri Rastgele Erişim depolanmış program (RASP) makine modeli gerçek mikroişlemcilerin nasıl çalıştığına yakın ve talimat seti sadece koşullu atlama içeriyor (özyineleme yok). Kodu dinamik olarak kendi kendine değiştirme olasılığı, alt rutinleri ve yinelemeli çağrıları uygulama görevini kolaylaştırır.

" Yinelemeli dönüşüm için özyinelemeli " hakkında birçok makale / makale bulabileceğinizi düşünüyorum (Dave'in cevabına veya yalnızca anahtar kelimelere bakın), ancak belki de daha az bilinen (ve pratik ) bir yaklaşım, özyinelemeli algoritmaların donanım uygulamasıyla ilgili en son araştırmadır ( doğrudan bir donanım parçasına "derlenen" VHDL dilini kullanarak ). Örneğin, V.Sklyarov'un " Özyinelemeli algoritmaların FPGA tabanlı uygulaması " makalesine bakın ( Kağıt, donanımda özyinelemeli algoritmalar uygulamak için yeni bir yöntem önermektedir. ... Veri sıralama ve sıkıştırma alanındaki özyinelemeli algoritmaların iki pratik uygulaması üzerinde çalışılmıştır. ayrıntılı olarak .... ).


1

Lambdaları destekleyen dillere aşina iseniz, yollardan biri CPS dönüşümüne bakmaktır. Çağrı yığını kullanımının kaldırılması (ve özellikle özyineleme) tam olarak CPS dönüşümünün yaptığıdır. Prosedür çağrılarını içeren bir programı sadece kuyruk çağrıları olan bir programa dönüştürür (bunları yinelemeli bir yapı olan gotolar olarak düşünebilirsiniz).

CPS dönüşümü, bir çağrı yığınını geleneksel bir dizi tabanlı yığın içinde açıkça tutmakla yakından ilişkilidir, ancak bir dizi yerine çağrı yığını bağlantılı kapaklarla temsil edilir.


0

bence bu soru hesaplama tanımlarının kökenlerine dayanıyor ve uzun zaman önce kilise lambda hesabı (özyineleme kavramını yüksek oranda yakalayan) Turing makinelerine eşdeğer olduğu ve içerdiği o zaman zarfında titizlikle kanıtlandı. hala kullanılan terminolojide "özyinelemeli diller / işlevler". Ayrıca görünüşe göre bu satırlar boyunca daha sonraki bir anahtar ref aşağıdaki gibidir

Peter Landin'in 1965 tarihli A makalesi ile ALGOL 60 ve Kilise'nin Lambda gösterimi arasındaki yazışmalar tarafından belirtildiği gibi, prosedürel soyutlama ve prosedür (alt program) uygulaması için temel mekanizmaları sağlayan lambda hesabı açısından sıralı prosedür programlama dilleri anlaşılabilir.

Bu konuda bkd çoğu bu wikipedia sayfasında kilise turing tezinde . kesin özelliklerinden emin değilim ama wikipedia makalesi, lambda hesabı ve turing makineleri arasındaki bu denkliği ilk kanıtlayan Rosser (1939) olduğunu gösteriyor. belki / muhtemelen makalesinde (muhtemelen özyinelemeli) lambda çağrılarını tm yapısına dönüştürmek için yığın benzeri bir mekanizma vardır?

Rosser, JB (1939). "Godel Teoreminin ve Kilise Teoreminin Kanıtlarının Gayri Resmi Sergisi". Sembolik Mantık Dergisi (Sembolik Mantık Dergisi, Cilt 4, Sayı 2) 4 (2): 53-60. DOI: / 2269059 10.2307. JSTOR 2269059.

modern Lisp dili ve varyant Şeması prensipleri ile ilgilenen herkes için elbette lambda hesabına güçlü bir benzerlik göstermektedir. ekspresyon değerlendirmesi için tercüman kodunun incelenmesi lambda calculus'un turing bütünlüğü için orijinal olarak makalelerde yer alan fikirlere yol açar.


1
Turing / lambda denklik kanıtı bu makalenin ekinde yer almaktadır: www.cs.virginia.edu/~robins/Turing_Paper_1936.pdf
Radu GRIG
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.