Download pdf - Prolog Recursion Lesson

Transcript
Page 1: Prolog Recursion Lesson

Recursion

Prolog Dersleri - 3.Hafta

Page 2: Prolog Recursion Lesson

Tekrarlama ve

rekürsiyon

Page 3: Prolog Recursion Lesson

Prosedür ve veri yapılarında tekrarlama iĢlemleri Visual Prolog‟da kolay bir şekilde yapılır. Bu bölümde önce tekrarlı işlemler (döngüler ve rekursif prosedürler), daha sonra ise rekursiv veri yapıları incelenecektir.

Page 4: Prolog Recursion Lesson

Tekrarlı İşlemler

Pascal, BASIC veya C gibi konvansiyonel programlama dilleriyle çalışanlar, Prologla çalışmaya başladıklarında FOR, WHILE, REPEAT gibi ifadeleri göremeyince şaşırabilirler. Çünkü Prologda iterasyonu anlatan direkt bir yol yoktur. Prolog sadece iki türlü tekrarlama-geriye dönüş imkanı tanır. Bu işlemlerde bir sorguya birden fazla çözüm bulmak ve bir prosedürün kendisini çağırdığı rekürsiyon işlemine imkan tanır.

Page 5: Prolog Recursion Lesson

Geriye İz Sürme

•Bir prosedür, istenilen bir hedef için uygun bir çözüm yerine alternatif başka çözümler aramak için geriye döner. Bunun için geriye henüz denenmemiş bir alternatifi kalan en son alt hedefe gidileceğini, bu noktadan tekrar aşağıya doğru inileceği bilinmektedir. Geriye dönüşü iptal edip tekrarlı işlemler yaptırmak mümkündür.

Page 6: Prolog Recursion Lesson

Örnek•PREDICATES

•nondeterm ulke_adi(symbol)

•ulke_adlarini_yaz

•CLAUSES

•ulke_adi("Türkiye").

•ulke_adi("Kazakistan").

•ulke_adi("Azerbaycan").

•ulke_adi("Amerika").

•ulke_adlarini_yaz:-

•ulke_adi(Ulke), write(Ulke), nl, fail.

•ulke_adlarini_yaz.

•GOAL ulke_adi(Ulke).

Yukarıdaki ulke_adi yüklemi sadece ülke isimlerini sıralar. Dolayısıyla GOAL ulke_adi(Ulke) şeklindeki bir hedefin birden fazla sonucu vardır ve ulke_adlarini_yaz yuklemi bunların hepsini görüntüler.

•ulke_adlarini_yaz :- ulke_adi(Ulke), write(Ulke), nl, fail. satırıyla söylenmek istenen şey şudur: “Bütün ülke isimlerini yazmak için, önce ulke-adi(Ulke) cümlesine cevap bul, bunu yaz, yeni bir satıra geç ve işlemi yeniden başlat.”

•„fail‟ komutunun programa yüklediği görev şöyle özetlenebilir: “GOAL cümlesine uygun bir çözüm bulunduğunda, geriye dönüş yap ve başka alternatiflere bak”.

•„fail‟ yerine, sonucu daima yanlış olan ve bu yüzden geriye dönüşü zorlayan başka bir alt hedef kullanmak mümkündür. Örneğin, 10=5+6 satırı her zaman yanlış olacağı için, Prolog başka alternatifler bulmak için daima geriye dönüş yapar.

Page 7: Prolog Recursion Lesson

•Örneğimizde ilk önce Ulke=Türkiye olur ve sonuç ekrana yazılır. „fail‟ komutuna sıra geldiğinde program, bir alt hedefe geri döner. Fakat nl veya write(Ulke) satırları için kullanılabilecek herhangi bir veri olmadığı için, bilgisayar ulke_adi(Ulke) iliĢkisi için baĢka çözümler arar.

•Ulke_adi(Ulke) iliĢkisi çalıĢtırıldığında, önceden boĢ değiĢken olan Ulke değiĢkeni „Türkiye‟ değerini almıĢtı. Bu yüzden bu iliĢkiyi yeniden kullanmadan önce Ulke değiĢkeni yeniden serbest hale getirilir. Daha sonra Ulke değiĢkeninin alabileceği baĢka bir olgu aranır. Ġkinci oluguda bu sağlanır ve ulke_adi yüklemindeki Ulke değiĢkeni „Kazakistan‟ değerini alır. Bu iĢlem böylece devam eder ve sonuçta Ģu satırlar görüntülenir.

•Türkiye

•Kazakistan

•Azerbaycan

•Amerika

•4 Solutions

•Eğer ulke_adlarini_yaz yüklemi „fail‟ komutundan sonra yazılmamıĢ olsaydı, cevap yine aynı olurdu fakat „yes‟ yerine „no‟ satırı görüntülenirdi.

Page 8: Prolog Recursion Lesson

Önceki ve Sonraki Eylemler Bir hedef için gerekli olan bütün çözümleri sağlayan bir program, çözüm yapmadan ve yaptıktan sonra başka şeyler de yapabilir. Örneğin

1. Yaşanacak güzel yerler

2. Ulke_adi(Ulke) yükleminin bütün sonuçlarını yaz.

3. Başka yerler de olabilir...

şeklinde bir mesaj yazarak bitirebilir.

Ulke_adlarini_yaz cümlesin ulke_adi(Ulke) yükleminin bütün sonuçlarını içerir ve sonunda bir bitiş mesajı yazar.

Örnekte geçen ilk ulke_adlarini_yaz cümlesi yukarıdaki adımlardan ikincisi içindir ve bütün çözümleri yazar. ikinci cümlesi ise üçüncü adıma tekabül eder ve sadece hedef cümlesini başarılı bir şekilde bitirmek içindir. Çünkü ilk cümle daima yanlıştır.

•Programı başka şekilde yazmak gerekirse:

•PREDICATES

•nondeterm ulke_adi(symbol)

•ulke_adlarini_yaz

•CLAUSES

•ulke_adi("Türkiye").

•ulke_adi("Kazakistan").

•ulke_adi("Azerbaycan").

•ulke_adi("Amerika").

•ulke_adlarini_yaz:-

•write("YaĢanacak bazı yerlerin listesi.."), nl, fail.

•ulke_adlarini_yaz :-

•ulke_adi(Ulke), write(Ulke), nl, fail.

•ulke_adlarini_yaz:-

•write("BaĢka güzel yerler de vardır..."), nl.

Page 9: Prolog Recursion Lesson

•İlk cümledeki „fail‟ komutu çok önemlidir. Çünkü bu komut ilk cümle çalıştırıldıktan sonra programın ikinci cümleye geçişini sağlar. Buradaki write ve nl http://alikoker.name.tr

•76

•komutlarının başka bir iş yapmaması çok önemlidir. Son „fail‟ komutundan sonra programın ikinci cümleciğe geçişi sağlanmalıdır.

Page 10: Prolog Recursion Lesson

Döngülü Geriye Dönüşün

Uygulanması Geriye dönüş işlemi bir hedefin bütün çözümlerinin bulunması açısından son derece

önemlidir. Birden fazla çözüm sunamayan hedefler için yine de geriye dönüş işlemi

yapılabilir. Bu da tekrarlama işlemini yapar. Örneğin:

tekrar.

tekrar:-tekrar.

gibi iki cümlecik sonsuz sayıda çözüm olduğunu göstermektedir.

Örnek:

PREDICATES

nondeterm tekrar

nondeterm karakteri_ekrana_yaz

CLAUSES

tekrar.

tekrar:-tekrar.

karakteri_ekrana_yaz:-

tekrar, readchar(Harf), /*Klavyeden girilen harfi oku ve C'ye ata*/

write(Harf),

Harf='\r', !. /* Satır sonu tuşuna (Enter/Return) basılmadıysa devam et*/

•GOAL karakteri_ekrana_yaz, nl.Yukarıdaki örnekte tekrar işleminin nasıl yapılacağını görülebilir. Karakteri_ekrana_yaz:-... kuralı, „Enter/Return‟ basılmadığı müddetçe, klavyeden girilen kararterleri kabul edip ekranda gösteren bir prosedür tanımlamaktadır.

•Karakteri_ekrana_yaz kuralının çalışma mekanizması şöyle sıralanabilir:

•1. tekrar‟ı çalıştır. (Hiçbir şey yapmaz)

•2. bir karakter oku (Harf)

•3. Harf karakterini yaz

•4. Harf‟in satır sonu karakteri olup olmadığını kontrol et.

•5. Eğer satır sonu elemanı ise, işlemi bitir, değilse, geriye iz sürme işlemini yap ve alternatif ara. Buradaki write ve readchar kurallarının hiçbiri alternatif sağlayamaz. Dolayısıyla geriye dönüş hemen tekrar kuralına gider, bunun ise alternatif sunması tabiidir.

•6. İşlem devam eder. Bir karakter oku, onu ekrana yaz, satır sonu elemanı olup olmadığını kontrol et.

Page 11: Prolog Recursion Lesson

Rekursif Prosedürler (A³)

● Kendisini çağırabilen prosedüre rekursif prosedür

diyoruz.

● Tekrarlama işlemin yapmanın diğer bir yolu da

rekursiyondur.

● Rekursif prosedürler yaptıkları işlerin sayısını, toplamını

veya işlmelerin ara sonuçlarını saklayabilir ve bunları bir

döngüden diğerine rahatlıkla aktarabilirler.

Page 12: Prolog Recursion Lesson

Örnek: N sayısının faktöryelini (N!) hesaplamak

Standart Sistem

● Başlangıç değeri 1 olan bir

return değişkeni oluştur.

● 1 den N e kadar bir döngü

oluştur.

● return değerini döngünün

indisi ile çarparak return

değişkenine ata.

● Sonuç return değişkenidir.

Rekursif Sistem

● Kural 1: N sayısı 0 ise sonuç

1 dir.

● Kural 2: N sayısı 0 den

büyük ise sonuç N-1

faktöryeldir ((N-1)!).

Page 13: Prolog Recursion Lesson

Örnek Kod

factorial(0,1).

factorial(N,F) :-

N>0,

N1 is N-1,

factorial(N1,F1),

F is N * F1.

Page 14: Prolog Recursion Lesson

Ama ??

Faktöriyel kuralını N=6 olacak şekilde

çağırılırsa, faktöriyel kendini N=5 için

çağırılacaktır. Bu durumda N deki 6 değeri

nereye gitti ?

Page 15: Prolog Recursion Lesson

Rekursif Prosedürlerin Avantajları

● Mantıksal olarak iterasyondan çok daha basittir.

● Listeleri işlemede çok yaygın olarak kullanılır.

● Rekursiyon işlemi özellikle probleme içerisinde dallanmaların mevcut

olduğu, yani bir problemin çözümünün bir alt probleme bağlı olduğu

durumlarda çok faydalıdır.

Page 16: Prolog Recursion Lesson

Sondan Rekursion Optimizasyonu

Rekursiyon işleminin en önemli dezavantajı, belleği fazlaca kullanmasıdır.

Bir prosedür başka bir alt prosedürü çağırdığında, çağrıyı yapan prosedürün

çağrıyı yaptığı anki çalışma durumu mutlaka kaydedilmelidir. Böylece çağrılan

işlemini bitirdikten sonra çağıran kaldığı yerden devam edebilir. Ama dallanma

çok fazla olursa hafızaya kaydettikleri de fazla olacağından bu bir hafıza

şişmesine bile neden olabilir.

Yani biz 6! i hesaplamak isterken otamatik olarak 5! , 4! , 3! , 2! , 1! , 0! i de

hesaplamış oluyoruz ve bu hesaplamalar için ekstradan hafızaya bunları atmış

oluyoruz.

Page 17: Prolog Recursion Lesson

Peki bunun için ne yapmalı?

Bir prosedürün, başka bir prosedürü kendisinin en son adımı olarak çağırdığını

düşünelim. Çağrılan prosedür görevini yaptıktan sonra, çağrıyı yapan prosedürün

yapması gereken başka bir şey kalmaz. Çağrıyı yapan prosedürün kendisinin çalışma

anını kaydetmesi gerekmez, çünkü o andaki bilgi artık gereksizdir. Çağrılan prosedür

biter bitmez, program akışı normal biçimde devam eder.

Bu durum daha açık olarak aşağıdaki şekilde ifade edilebilir. A prosedürünün B

prosedürünü, B prosedürünün ise C prosedürünü son adım olarak çağırdığını düşünelim.

B prosedürü C’yi çağırdığında, B’nin başka bir şey yapması gerekmez. Yani C‟nin o anki

çalışma durumunu B olarak kaydetmek yerine, B’nin kaydedilen eski durumun C’ya

aktarmak, depolanan bilgi içinde uygun değişiklik yapmak mümkündür. C bittiği zaman,

doğrudan A prosedürü tarafından çağrılmış gibi olacaktır.

Page 18: Prolog Recursion Lesson

Sondan Rekursiyonun Kullanımı

Prologda bir prosedürün başka bir prosedürü ‘kendisinin

en son adımı olarak çağırması’ bu prosedürü sondan

rekursiyon yapacaktır. Bu da bu prosedürün geriye dönüş

yapması olasılığını kaldırır. (Yani heryede kullanamayız.)

######yani

sayac(Sayi):-

write(Sayi), nl,

yeni_sayi=Sayi+1,

sayac(Yeni_sayi).

Page 19: Prolog Recursion Lesson

Sondan Rekursiyonu Engelleme

Engellemek için :

● Başka prosedürü son adımda çağırmamak.

● Başka bir alternatif bırakmak.

(Bu ne midir? *)

Page 20: Prolog Recursion Lesson

Rekursiyonda Cut Kullanımı

Rekursif Prosedürleri çalıştırırken bazı noktalarda durdurmamız gerekir. bunun

için içinde bir koşul yazarak bu prosedürü durdurabiliriz.sayac(Sayi):-

Sayi>=0,!, /*Burada sayı 0 dan küçük olma durumunda boş bir sonuç döndürür*/

Sayi<1000,!, /*Burada ise sayı 1000 i geçtiği takdirde programı sonlandırması için*/

write(Sayi),

write(","),

Ysayi is Sayi+1,

sayac(Ysayi).

sayac(_):-

write("Sayi negatiftir.").

Page 21: Prolog Recursion Lesson

swipl_hakkinda.pl #oguzhancoo

%Değişken tanımları

?- assert(like(x,y)). %kabukta

like(x,y). %dosyada

Page 22: Prolog Recursion Lesson

%kabukta dosya çağırırken

?- [‘dosya.pl’].

%Konsole’da çalıştırırken

swipl -f dosya.pl

Page 23: Prolog Recursion Lesson

Args On The Loop%factorial

fact(Num,NumF):-

m_fact(Num,NumF,1,1).

m_fact(Num,NumF,I,P):-

I<=Num,!,

NewP=P*I, %kendisini yeni değerlerle çağırır

NewI=I+1, % //

m_fact(Num,NumF,NewI,NewP).

m_fact(Num,NumF,I,P):-

I>Num,

NumF=P.

%P=P+1 prologda değişken ataması yapmaz.

%YP = P+1 şeklinde yeni bir değişken sorunu çözecektir.

Page 24: Prolog Recursion Lesson

fact.pl%factorial

factorial(N,Fact) :-

fact_iter(N, 1, Fact).

fact_iter(0, SoFar, SoFar) :- !.

fact_iter(N, SoFar, Ans) :-

N1 is N - 1,

SoFar1 is N * SoFar,

fact_iter(N1, SoFar1, Ans).

%source http://www.cs.toronto.edu/~sheila/384/w11/simple-prolog-examples.html

Page 25: Prolog Recursion Lesson

hanoi.pl%hanoi towers

move(1,X,Y,_) :-

write('Disk '),

write(X),

write(' ten '),

write(Y),

write(' ye taşındı.'),

nl.

move(N,X,Y,Z) :-

N>1,

M is N-1,

move(M,X,Z,Y),

move(1,X,Y,_),

move(M,Z,Y,X).

Page 26: Prolog Recursion Lesson

Recursive Data Structures

Page 27: Prolog Recursion Lesson

recursive_exmp.pl

%A(B(D,E),C(F,G))

A

B C

D E F G

%Depth First Searching

Page 28: Prolog Recursion Lesson

tree_exmp.pl%DOMAINS

agac_yapisi=agac(string, agac_yapisi, agac_yapisi); bos_dal

%PREDICATES

agaci_tara(agac_yapisi)

%CLAUSES

agaci_tara(bos_dal).

agaci_tara(agac(Isim, Sol, Sag)):-

write(Isim, '\n'),

agaci_tara(Sol), agaci_tara(Sag).

%GOAL

agaci_tara(agac("Emine", agac("Ali", agac("Hasan", bos_dal, bos_dal),agac("Fatma", bos_dal, bos_dal)), agac("Ayse",

agac("Fuat", bos_dal, bos_dal),agac("Leyla", bos_dal, bos_dal)))).

Page 29: Prolog Recursion Lesson

swipl -s tree.exmp.pl ?-agaci_tara(agac("Emine", agac("Ali", agac("Hasan", bos_dal, bos_dal),agac("Fatma", bos_dal, bos_dal)),

agac("Ayse", agac("Fuat", bos_dal, bos_dal),agac("Leyla", bos_dal, bos_dal)))).

Emine

Ali

Hasan

Fatma

Ayse

Fuat

Leyla

yes

?-

Page 30: Prolog Recursion Lesson

ağaç oluşturmak

#s

Ağaç biçiminde bir yapı oluşturmanın bir yolu

operatörlerden ve argümanlardan oluşan iç içe

geçmeli bir yapı yazmaktır.

Page 31: Prolog Recursion Lesson

agac_olustur(Sayi, agac(Sayi, bos_dal, bos_dal))

# Eğer Sayi bir sayı ise, agac(Sayi, bos_dal,

bos_dal) tek hücreli bir ağaç olup veri olarak bu

sayıyı içerir.

Page 32: Prolog Recursion Lesson

sola_yerlestir(Sayi, agac(A, _,B), agac(A,Sayi,B))

#İlk ağacı, ikinci ağacın alt dalı olarak alır ve üçüncü ağacı

da sonuç olarak verir.

Page 33: Prolog Recursion Lesson

domains

agac_yapisi=agac(string,agac_yapisi,agac_yapisi)

Page 34: Prolog Recursion Lesson

tek daldan oluşan ağaç

agac_olustur(String, deger)

Page 35: Prolog Recursion Lesson

dal birleştirme

sola_yerlestir(deg1,degx,degy)

saga_yerlestir(deg1,degx,degy)

Page 36: Prolog Recursion Lesson

Recommended