Prolog

arago_W&B

Üye
1 Mar 2008
139
3
Günümüzde bilgisayar alanında gözlenen hızlı değişim, yeni teknolojik imkanların ortaya çıkmasına neden olmaktadır. İnsanoğlu daha bundan birkaç yıl öncesinde hayal edemediği gelişmelerin günümüzde gerçekleştiğini gördükçe hayretler içerisinde kalmaktadır. Bilgi teknolojiyle yakından ilgilenenler dahi, bu hızlı değişime ayak uydurmada zorlanabilmektedir.
Bilgisayarların insanlar gibi düşünmesine sağlamak için yoğun çalışmalar sürdürülmededir. Mümkün olduğunca insan beyni fonksiyonlarına yakın işlevleri yerine getirebilecek mikroişlemcilerin tasarımı üzerinde çalışmalar sürdürülmektedir. Bu çalışmalar beşinci kuşak bilgisayar dönemine rastladığı ve bu kuşak içerisinde Yapay Zeka (Artificial Intelligece) alanlarında önemli gelişmelerin yer aldığı görülür.
Bilgi teknolojisinin amacı, uzman kişilerin bilgilerini bilgisayarda kullanarak yeni sonuçlar elde etmektir. Uzman sistemler, yapay zekanın bir dalı olup, bir probleme uzman insan düzeyinde bir çözüm bulmak için uzman bilgisini kullanırlar.
Yapay zekada sık kullanılan programlama dillerinden biri de Prolog dilidir. Son versiyonu Visual Prolog olarak piyasaya çıkartılmıştır. Visual Prolog, ifadeler mantığının kullanarak, bilgisayara çözümü aranan problem hakkında bilinen gerçekleri ve kuralları vererek, uygun bir çözüm elde edilmesine sağlar.
Konvansiyonel programlama dillerinde, bir programcı herhangi bir problemin nasıl çözüleceğini bilgisayara adım adım tanıtmak zorundadır. Oysa bir Visual Prolog programcısının yapması gereken şey, çözüm aranan problem hakkında bilinen gerçekler ve kuralları, bunlar arasındaki ilişkileri tanımlamak, daha sonra mümkün olana bütün çözümleri bulmak görevini Prolog’a vermektir. Visual Prolog, aritmetik işlemlerin yapılmasına da imkan tanır.
Visual Prolog, C++ ve diğer bilinen programlama dilleri kadar hızlı çalışır. Hızlı bir derleyici, bilgisayar dünyasında daima aranan bir avantaj olmuştur. Visual Prolog, MS DOS, Windows 3.1, Windows 95, Windows NT, Unix ve OS/2 işletim sistemleri altında programlamaya imkan tanıyan bir çoklu ortam programlama dilidir.
Uzman sistemlerin, bütün kullanıcılara düşük maliyetli uzmanlık, insanlar için tehlikeli olan ortamlarda riski azaltma, emekli olabilen veya vefat edebilen insan uzmanlar yerine, her zaman kalıcı olan uzmanlar ve verilen kararların net açıklanabilmesi gibi güzel özellikleri vardır.
Bu çalışma, yapay zeka alanında çalışma yapan, uzman sistem tasarlamak isteyen fakat Türkçe kaynak bulamayan, kaynak kullanarak Prolog dilini öğrenmek isteyen araştırmacılara faydalı olmak amacıyla gerçekleştirilmiştir. Prologun temel mantığı, elemanların ayrıntılı anlatımı, Prologun en önemli özelliklerinden biri olan Geriye İz Sürme ve bu konuların açık biçimde kullanıldığı örnekler doyurucu bilgi sunmaktadır.
Anahtar Kelimeler: Uzman Sistemler, Yapay Zeka, Visual Prolog, Programlama Dilleri
 

arago_W&B

Üye
1 Mar 2008
139
3
1. GİRİŞ


İngilizce Expert System kelimelerinden türetilerek Türkçe’ye kazandırılmış olan Uzman Sistem yazılımları alanında, ülkemizde yoğun çalışmaların yapıldığı gözlenmektedir.
Bir Uzman Sistem, Bilgisayar Destekli Eğitim amaçlı da kullanılabileceğine göre, eğitim ve öğretim için gerekli olabilecek her türlü formasyonu taşımalıdır. Öğrenme, doğrudan bilgisayardan yapılacağı için, klasik öğretmen merkezli eğitime nazaran, içeriğin daha doyurucu ve cazip özellikler taşıması gerekir. Cazip unsurlar, bilgisayar tarafından yönetilmeli ve uygun ortamlarda ekranda veya bilgisayarın çevre birimlerinde ortaya çıkabilmelidir.
Öğretilmek istenen bir konuda işlem basamaklarının sırası çok önemlidir. Öğrenciye yöneltilecek sorular çok iyi belirlenmeli ve soru sorarken öğretme mekanizması devreye alınmalıdır. Soruların sıralanışında yeterli hassasiyet gösterilmediği takdirde, hem öğrenme eksik olabilir, hem de öğrenci yanlış bilgilendirmeye sevk edilebilir.
Uzman sistem üzerinde çalışan öğrenci, bilgisayarı ile yalnız başına kalacaktır. Sürekli monoton bir ekran görüntüsü yüzünden, öğrencinin öğrenme arzusu kırılabilir, bilgisayar önünde canı sıkılabilir. O halde öğretme esnasında, öğrencinin dikkatinin konuya sevk edilebilmesi için, program arasında görsel ve işitsel yöntemlerle uygun uyarılar yapılabilmelidir.
Bilgisayar destekli eğitimin kullanılabileceği her yere ilave olarak, problemlere çözüm getirilmek istenen her sahada Uzman Sistem kullanılabilir.
Bir Uzman Sistem hazırlanırken asgari olarak aşağıdaki hususların göz önünde bulundurulması gerekir.
  • Hazırlanacak proje konusu hem güncel olmalı hem de o konuda yeterli kaynak bulunabilmelidir.
  • Konunun bol miktarda resim ve şekil içermesi, kullanıcının öğrenme hızını artıracak bir faktördür.
  • Proje başlangıcında, güzel bir sunu yazılımıyla (örneğin Power Point gibi) proje hakkında özet bilgiler verilmeli, proje tasarımcısı ve denetleyen kişilerin isimleri, resimleri ve faydalanılan kaynaklar hakkında bilgi verilmelidir.
  • Konu anlatımına geçmeden önce, güzel bir müzik eşliğinde bilgisayar, kullanıcının ismini girmesini istenmelidir. Çünkü ilerleyen konular içerisinde bazı yerlerde esprili cümlelerle bilgisayarın kullanıcıya ismi ile hitap etmesi, kullanıcının aniden dikkatini çekmeye neden olabilmekte ve kullanıcı bu durumdan fazlasıyla memnun kalabilmektedir.
2. PROLOG’UN (PROGRAMMING IN LOGIC) TEMELLERİ

Bir Prolog programı, (Basic, Fortran, Pascal, C) olduğu gibi bir dizi komut satırından değil, doğruluğu önceden bilinen gerçeklerden ve bu gerçeklerden bilgi sağlamaya yarayan kurallardan oluşur.
Prolog, cümlecikler (Horn Clauses) üzerine bina edilmiştir. Cümlecikler, yüklem mantığı denilen formal sistemin bir alt kümesidir.
Prolog’da bir Karar Motoru (Inference Engine) vardır. Bu motor, verilen bilgiyi kullanarak cevabı aranan bir problem için, mantıksal bir şekilde karar veren bir işlemdir. Karar motorundaki Kalıp Eşleştirici (Pattern Matcher) sorulara uygun olan cevapları eşleştirerek önceden bilinen ve program içine kaydedilen bilgiyi geri çağırır. Prolog, program satırları içinde sorulan bir soruyu veya hipotezi doğrulamak için, doğruluğu önceden bilinen ve veri olarak yüklenmiş olan bilgi kümesini sorgulayıp hipotezin doğruluğu hakkında karar vermeye çalışır. Kısaca söylemek gerekirse, bir Prolog programının temelini, program akışı içinde önceden verilen gerçekler ve kurallar oluşturur.
Prolog’un önemli diğer bir özelliği de şudur: Sorulan sorulara mantıklı cevaplar bulmanın yanısıra, bulduğu tek bir çözümle yetinmez, başka alternatifleri de inceleyerek mümkün olan bütün çözümleri bulur. Prolog, bir programın birinci satırından başlayıp sonuncu satırına kadar ilerleyip sadece bir çözüm bulmak yerine, zaman zaman geriye dönüş yaparak problemin her bir bölümünün çözümü için alternatif yolları da arar.
Yüklem mantığı, mantığa dayalı fikirleri yazılı bir şekilde ifade etmeye yarayacak şekilde geliştirilmiştir ve Prolog’da bu mekanizma gayet iyi kullanılır. Yüklem mantığının yaptığı ilk iş, cümlelerdeki gereksiz kelimeleri ayıklamaktır. Daha sonra cümleler-kelimeler arasındaki ilişkiler ilk sıraya, nesneler ise ilişkilerden sonra sıralanır. Bu nesneler ise ilişkilerin etkili olduğu argümanlar olarak yazılır.
Konuşma Dili Prolog’daki Karşılığı
Ahmet bir insandır. insan(Ahmet).​
Gül kırmızıdır. kirmizi(gul).​
Ahmet, gülü kırmızı ise sever. sever(Ahmet, gul) if kirmizi(gul).​
Prolog ile program yazarken, ilk önce nesneler ve bu nesneler arasındaki ilişkiler tanımlanır. ‘Ahmet gülleri sever’ cümlesindeki Ahmet ve gül kelimeleri nesne, ‘sevmek’ ise bu iki nesne arasındaki ilişkidir. Bu ilişkinin ne zaman doğru olacağını belirleyen ifadeye ise Kural denir. ‘Ahmet, gülü kırmızı ise sever’ cümlesindeki ‘sevmek’ hangi durumda Ahmet’in gülü seveceğini belirttiği için bu durumda Kural olur.
2.1. Gerçekler: Bilinen olgular

Prolog’da, nesneler arasındaki ilişkiye Yüklem denir. Tabii dilde bir ilişki bir cümle ile sembolize edilir. Prolog’un kullandığı yüklem mantığında ise bir ilişki, bu ilişkinin ismi ve bunu takiben parantez içinde yazılan nesne veya nesnelerden oluşan basit ifadelerle özetlenir. Gerçekler, tıpkı cümlelerdeki gibi ‘.’ ile biter. Aşağıdaki örneklerde ‘sevmek’ fiilinin tabii dilde ifade edilmesi gösterilmiştir.
Yasin Esra’yı sever.
Esra Cihat’ı sever.
Yasin kedileri sever.
Yukarıdaki ifadeleri olgu olarak kabul edip Prolog’daki karşılıklarını yazalım:
sever(yasin, esra).
sever(esra, cihat).
sever(yasin, kediler).
Görüldüğü gibi, gerçekler nesnelerin ve ilişkilerin değişik özelliklerini de ifade edebilirler.
2.2. Kurallar: Verilen Gerçeklerden Hüküm Çıkarma

Kurallar, gerçek olguları kullanarak bir sonuca varmak için kullanılır. Aşağıda ‘sevmek’ ilişkisinden elde edilen bazı kurallar verilmiştir:
Yasin, Esra’nın sevdiği her şeyi sever.
Hasan kırmızı olan her şeyi sever.
Bu kuralları Prolog dilinde yazmak gerekirse:
sever(yasin, hersey):-sever(esra, hersey).
sever(hasan, hersey):- kirmizi(hersey).
Buradaki :- sembolü, prosedürel dillerdeki if(eğer) anlamında olup, bir kuralın iki parçasını birleştirir.
Prolog, sever(yasin, hersey):-sever(esra, hersey) kuralını kullanarak, Yasin’in sevdiği nesneyi bulmak için önce kuralın ikinci kısmını, yani Esra’nın sevdiği nesneyi bulur. Bunun doğruluğu ispatlandıktan sonra Yasin’in sevdiği nesneyi belirler.
2.3. Sorgulamalar: (Querries)

Prolog’a bazı gerçekler tanıtıldıktan sonra, artık bu gerçeklerle ilgili sorular sormaya başlanabilir. Bunu Prolog Sistemini Sorgulama diyoruz. Veri olarak saklanan gerçekler ve gerçekler arasındaki ilişkiler bilindikten sonra, bu ilişkiler hakkında soru sorup cevap almak kolaydır.
Günlük konuşmalarda Esra Yasin’i seviyor mu? şeklindeki bir soruyu Prolog’da şöyle ifade edilir.
sever(esra, yasin).
Bunun cevabı program akışı içerisinde verdiğimiz gerçeklere bağlıdır. Yasin neyi sever? şeklindeki bir soruyu Prolog’a sormamız mümkündür. Bunu sever(yasin, Neyi) şeklinde kodlarsak, Prolog’dan şu cevabı alırız:
Neyi=esra
Neyi=kediler
2 Solutions
Çünkü önceden verilen sever(yasin, esra) ve sever(yasin, kediler) ilişkileri, bunu ispatlamaktadır.
Burada Yasin ve Esra'ın küçük harfle, Neyi kelimesinin ise büyük harfle başlamaktadır. Çünkü, yüklemdeki Yasin sabit bir nesnedir, yani değeri sabittir. Oysa Neyi bir değişkendir. Yani farklı gerçeklerle beraber, sorgudan alınacak cevaplar da farklı olacaktır. Bu yüzden değişkenler daima büyük harf veya bir ‘_’ ile başlar.
 

arago_W&B

Üye
1 Mar 2008
139
3
Bu durumda Neyi kelimesinin cevapları değişebilir. Prolog bir sorguya cevap ararken daima önceden verilen gerçeklerin ilkinden başlar ve hiçbirini ihmal etmeden en sondaki gerçeğe kadar ilerler.
Prolog’da, bir insana sorulabilecek başka soruları da sormak mümkündür. Fakat ‘Mehmet hangi kızı sever?’ şeklindeki bir soruya hiçbir cevap alınamaz. Çünkü yukarıdaki satırlar dikkate alındığında, bu konuyla ilgili bir bilginin mevcut olmadığı görülür. Yasin Esra’yı sevmektedir, fakat Esra’nın kız olduğuna dair bir bilgi mevcut olmadığından, Prologun bu gerçeklerden hareketle bir karara varması mümkün olamaz.
2.4. Gerçekler, Kurallar ve Sorgulamaların Bir Araya Yazılması

1. Aşağıdaki gerçekler ve kuralların var olduğunu kabul edilsin.
Büyük araba hızlıdır.
Büyük bir araba iyidir.
Küçük bir araba daha kullanışlıdır.
Kasım, eğer hızlı ise, büyük arabayı ister.
Yukarıdaki gerçeklerden anlaşılan şey, Kasım’ın hızlı ve büyük arabalardan hoşlandığıdır. Prolog da aynı sonuca varacaktır. Zaten hızlı arabalar hakkında bilgi verilmeseydi, hiçkimse Kasım’ın hızlı arabalardan hoşlandığı sonucuna varamazdı. Yapılabilecek tek şey, ne tür bir arabanın hızlı olacağını tahmin etmektir.
  1. Aşağıdaki örneğe bakarak, Prolog’un kuralları kullanarak sorgulara nasıl cevap bulduğu açıklanmıştır.
hoslanir(cengiz, masa_tenisi).
hoslanir(mehmet, yuzme).
hoslanir(yavuz, futbol).
hoslanir(levent, Spor):-hoslanir(yavuz, Spor).
Son satırdaki hoslanir(levent, Spor):-hoslanir(yavuz, Spor) bir kural olup, konuşma dilindeki karşılığı şudur: Levent, bir spor türünden eğer Yavuz da hoşlanıyorsa hoşlanır.
Bu kuralın baş tarafı hoslanir(levent, Spor) ve gövde kısmı hoslanir(yavuz, Spor) olur. Burada Levent’in yüzmeyi sevip sevmediği hakkında hiçbir bilgi yoktur. Bunu öğrenmek için hoslanir(levent,yuzme) şeklinde bir sorgu kullanmak yeterlidir. Cevap bulmak için Prolog hoslanir(levent, Spor):-hoslanir(yavuz, Spor) kuralını kullanır. Yukarıda geçen gerçeklerle bunlar arasındaki ilişkiler, aşağıdaki şekilde bir program haline getirilir
PREDICATES
nondeterm hoslanir(symbol,symbol)
CLAUSES
hoslanir(cengiz, masa_tenisi).
hoslanir(mehmet, yuzme).
hoslanir(yavuz, futbol).
hoslanir(levent, Spor):- hoslanir(yavuz, Spor).
GOAL hoslanir(levent, futbol).
Bu program Prolog’da derlenirse, ‘yes’ cevabını alınır. Çünkü hoslanir(yavuz, futbol) gerçeği Yavuz’un futboldan hoşlandığını göstermektedir. hoslanir(levent, Spor):-hoslanir(yavuz, Spor) kuralı ise Levent’in, Yavuz’un yaptığı spor türlerinden hoşlandığını göstermektedir. İlgili olgu Yavuz’un futboldan hoşlandığını gösterdiği için, Levent’in de futboldan hoşlandığını söylemek mümkündür. Bu yüzden GOAL hoslanir(levent, futbol) sorgusunun cevabı ‘yes’ olur.
Fakat hoslanir(levent, tenis) sorgusunun cevabı ‘no’ olacaktır. Çünkü:
  1. Bu sorgunun doğrulanabilmesi için gerçekler arasında öncelikle Yavuz’un tenisten hoşlandığını gösteren bir olgunun var olması gerekir.
  2. hoslanir(levent,Spor):-hoslanir(yavuz, Spor) kuralı, üstteki gerçekleri kullanarak bu konuda bir karara varamaz. Çünkü kuralın gövdesini doğrulayacak bir bilgi olmadığından, kural başarısız olur.
2.5. Değişkenler: Genel Cümleler

Prolog’da değişkenler kullanılarak genel gerçekler, kurallar yazılabilir ve genel sorular sorulabilir. Değişkenler tabii dilde de kullanılır. Tipik bir örnek vermek gerekirse:
Kasım, Ferit’in sevdiği şeyi sever.
Bu bölümün başında da belirtildiği gibi, Prolog’da değişkenler daima büyük harf veya bir ‘_’ ile başlar. sever(kasim, Sey):-sever(ferit, Sey) şeklinde ifade edilebilecek yukarıdaki cümlede, Sey değişkendir. kasim ve ferit kelimeleri sabit semboller oldukları için küçük harfle başlarlar. Bu sabitleri de ekrana büyük harfle başlayacak şekilde yazmak mümkündür. Bunun için sadece (“Kasim”, Sey) veya (“Ferit”, Sey) şeklinde yazmak yeterlidir.
2.6. Bölüm Özeti

  1. Bir Prolog programı iki tür ifadelerden oluşur: Gerçekler ve Kurallar.
  • Gerçekler, programcının doğruluğundan emin olduğu bilgiyi ilişkiler veya özellikler olarak anlattığı satırlardır.
  • Kurallar, bağımlı ilişkilerdir. Prolog bu kuralları kullanarak bir bilgiden hareketle bir konuda karar verir. Bir kural, verilen şartlar yerine geliyorsa başarılı olur, yani doğru olur.
  • Prolog’da bütün kuralların iki kısmı vardır: Baş ve Gövde kısmı. Bunlar birbirinden :- sembolleri ile ayrılırlar.
  • Baş kısmı verilen gerçekler doğrulanıyorsa doğrudur. Bu kısım aynı zamanda sonuç veya bağımlı ilişki olarak da bilinir.
  • Gövde kısmı ise doğru olması gereken şartları taşır. Böylece Prolog, programın baş kısmının doğru olduğunu ispatlayabilir.
  1. Gerçekler ve kurallar birbirinin aynısıdır. Gerçeklerin kurallardan tek farkı, açıklayıcı bilgi taşıyan gövdelerinin olmamasıdır.
  2. Prolog’a bir dizi gerçek veya kural tanıttıktan sonra, bu gerçekler veya kurallar hakkında soru sormak mümkündür. Buna Prolog Sistemini Sorgulama denir. Prolog, sorgulama esnasında, verilen gerçekler listesinin başından sonuna kadar tarama yapar ve sorguya uyan cevapları bulmaya çalışır.
  3. Prolog’daki Karar Motoru bir kuralın baş ve gövde kısmını incelerken, bilinen gerçek ve kurallara başvurur. Şartların yerine gelip gelmediğini kontrol eder. Bir kuraldaki bütün şartlar doğrulandıktan sonra, bağımlı olan kısım, yani kuralın baş kısmının doğru olduğuna karar verir. Bütün şartlar, bilinen gerçeklere göre karşılanamazsa, sorguya olumlu cevap verilemez.
Örnekler:
Prolog gerçeklerinin konuşma diline çevrilmesi, aşağıda verilmiştir.
  1. yapmaktan_hoslanir(oya, resim) = Oya, resim yapmaktan hoşlanır.
  2. cocuk(arif).= Arif, bir çocuktur.
  3. bulunur(“Çankaya Köşkü”, “Ankara”). = Çankaya Köşkü Ankara’dadır.
  4. adres(abuzer, zonturlu, “ Fatih Cad. 6. Sokak.”, “Dışkapı”, “ANKARA”, 06412).= Abuzer Zonturlu’nun adresi Fatih Cad. 6. Sokak Dışkapı, ANKARA, 06412’dir.
Şimdi tam tersini yapalım, konuşma dilinden Prolog diline çevrilme ise, aşağıdaki gibi yapılır.
  1. Vedat iyi kebap yapar = yapar(vedat, iyi_kebap).
  2. Keban Barajı Elazığ’dadır = bulunur(“Keban Barajı”, “Elazığ”).
  3. Kasım Kaya’nın telefon numarası 314 41 17’dir. telefon_no(“Kasım KAYA”, “314 41 17”).
  4. Hüseyin Meryem’in babasıdır. = baba(huseyin, meryem).
2.7. Konuşma Dilindeki Cümlelerin Prolog Programlarına Aktarılması

Bu bölümün ilk kısmında gerçekler, kurallar, ilişkiler, genel cümleler ve sorgulamalar konusunu incelenmiştir. Aynı kelimeler üzerinde çalışmakla beraber, Prolog’la daha fazla ilgili kelimeler üzerinde, yani cümlecikler, yüklemler, değişkenler ve hedefler üzerinde durulacaktır.
2.8. Cümleler (Gerçekler ve Kurallar)

Prolog dilini oluşturan iki türlü ifade vardır. Bu ifadeler gerçekler veya kurallardan ibarettir. Prolog dilinin kalbini oluşturan bu ifadelere clause denilmektedir.
Bir gerçek, bir nesnenin veya nesneler arasındaki ilişkinin bir özelliğinin sadece tek bir yönünü temsil eder. Bir gerçeğin Prolog tarafından tamamen doğru kabul edildiğini, bir sorgulamaya cevap ararken bu gerçeklerden yola çıkıldığını ve bu gerçeklerin doğruluğunun kontrol edilmediği unutulmamalıdır.
Günlük hayatımızda da doğruluğu bilinen gerçeklerden yola çıkarak bir şeyin doğru olup olmadığı araştırlır. İşte, mevcut gerçeklerden hareket ederek neyin doğru olabileceğini gösteren yapıya Prolog’da Kural denir. Şimdi Prolog’daki Kural yapısına bir örnekle yakından bakalım. Örnek:
  1. Aşağıdaki cümlede, menü’de olan bir yemeğin Mehmet’e uygun olup olmadığı sorgulanmaktadır.
Mehmet ülser olduğu için sadece doktorunun izin verdiği yemekleri yer.
Menü ve yukarıdaki kurala bakarak, Mehmet’in hangi yemeği sipariş edebileceğine karar verilebilir. Bunu yapabilmek için, menüdeki yemeğin belirli şartları taşıyıp taşımadığına bakılmaladır.
  1. Menudeki_yemek bir sebze mi?
  2. Menudeki_yemek doktorun tavsiye ettiği listede var mı?
  3. Sonuç: Eğer a ve b şıklarının ikisinin de cevabı ‘Evet’ ise, bu durumda Mehmet menüdeki bu yemeği yiyebilir.
Prolog’da bu tür ilişkilerin bir kuralla ifade edilmesi zorunludur, çünkü verilecek karar tamamen gerçeklere bağlıdır. Yukarıdaki ifadeler; Prolog gerçekleri olarak şöyle yazılabilir:
mehmet_yiyebilir(Menudeki_yemek):-
sebze(Menudeki_yemek), doktor_tavsiyeli(Menudeki_yemek).
sebze(Menudeki_yemek) ifadesinden sonra ‘,’ konulmuştur. Çünkü virgül, iki amaç arasındaki bağlantıyı gösterir ve ‘and’ anlamındadır. mehmet_yiyebilir(Menudeki_yemek) ilişkisinin doğrulanabilmesi için, sebze(Menudeki_yemek), doktor_tavsiyeli(Menudeki_yemek) ilişkilerinin her ikisinin de doğru olması gerekir.
Örnek:
Ebeveyn ilişkisini anlatan bir Prolog gerçeği aşağıdaki gibi yazılır.
ebeveyn(omer, nejla) = Omer, Nejla’nın ebeveynidir.
Programın veritabanında babalık durumunu gösteren gerçeklerin zaten var olduğunu, yani baba(omer, nejla) gerçeğinin mevcut olduğu ve aynı zamanda annelik ilişkisini de gösteren anne(leyla, nejla) gerçeğinin de var olduğu kabul edilsin. Babalık veya annelik bağı hakkında yeterince bilgi olduğundan, ayrıca baba ve anne bilgilerini anlatmak vakit kaybına neden olur. Bunu yerine genel bir kural yazmak daha mantıklıdır. Yani,
ebeveyn(Sahis1, Sahis2):-baba(Sahis1, Sahis2).
ebeveyn(Sahis1, Sahis2):-baba(Sahis1, Sahis2).
Örnek:
Bir müşteri arabayı severse ve araba satılık ise bu arabayı satın alabilir.
Tabii dildeki bu ilişki, aşağıdaki kuralla Prolog’a aktarılabilir:
satin_alabilir(Musteri, Model):-
sahis(Musteri), araba(Model), hoslanir(Musteri, Model), satilik(Model).
Aynı kural, konuşma dilinde aşağıdaki şekilde ifade edilir.
Müşteri modeli satın alabilir :-
Müşteri bir şahıs ve
Model bir araba ve
Müşteri modelden hoşlanırsa ve
Model satılık ise.
Bu kuralın baş kısmı, gövde kısmındaki her dört şartın da doğrulanması halinde doğru olacaktır. Yukarıda yazılan gerçekler, aşağıdaki şekilde program haline getirilebilir.
PREDICATES
nondeterm satin_alabilir(symbol, symbol)
nondeterm sahis(symbol)
nondeterm araba(symbol)
hoslanir(symbol, symbol)
satilik(symbol)
CLAUSES
satin_alabilir(X,Y):-
sahis(X),
araba(Y),
hoslanir(X,Y),
satilik(Y).
sahis(ahmet).
sahis(paki).
sahis(cengiz).
sahis(levent).
araba(buick).
araba(bmw).
araba(passat).
araba(toyota).
hoslanir(paki,buick).
hoslanir(levent, toyota).
hoslanir(cengiz, passat).
hoslanir(ahmet, tenis).
satilik(pizza).
satilik(toyota).
satilik(buick).
satilik(passat).
 

arago_W&B

Üye
1 Mar 2008
139
3
Yukarıdaki programı yazdıktan sonra Levent ve Cengiz’in ne satın alabileceğini, kimin buick marka arabayı alabileceğini bulmak için aşağıdaki hedef cümleleri kullanılabilir:
satin_alabilir(Kim, Ne).
satin_alabilir(levent, Ne).
satin_alabilir(cengiz, Ne).
satin_alabilir(Kim, buick).
2.9. Olgular Arasındaki İlişkiler: Yüklemler (Predicates)

Bir ilişkinin sembolik ismine yüklem denir ve yükleme bağlı olan nesnelere argüman denir. Mesela sever(yasin, esra) gerçeğindeki sever ilişkisi yüklem, yasin ve esra ise bu yüklemin agrümanları olan nesnelerdir.
Argümanlı ve agrümansız yüklem örnekleri:
sahis(soyad, ad, cinsiyet). sahis yüklem; soyad, ad, cinsiyet ise bu yüklemin argümanlarıdır.
basla = argümanı olmayan yüklem
dogum_gunu(isim, soyisim, tarih). Dogum_gunu yüklem, isim, soyisim ve tarih nesneleri ise argümanlarıdır. Sınırlı olmakla beraber, bir yüklem argümansız olarak da kullanılabilir.
2.10. Değişkenler (Genel Cümleler)

Basit bir sorgulamada, sever(Kim, tenis) kuralını kullanarak kimin tenis oynamaktan hoşlandığı öğrenilebilir. Bu sorguda Kim, değişken olarak kullanılmıştır. Visual Prolog’da değişken isimlerinin daima büyük harfle veya ‘_’ ile başladığı, daha önceden söylenmişti. İlk karakteri büyük bir harf veya ‘_’ olmak şartıyla, değişkenler istenilen kadar rakam, büyük veya küçük harf alabilirler. Konu ile ilgili birkaç örnek, aşağıda verilmiştir.
Geçerli Değişkenler Geçersiz Değişkenler
Prolog_ile_yazdigim_ilk_program 1.deneme​
_14_10_1978_tarihinde_doganlar 14.program​
_1_nolu_ogrenci “prolog”​
Değişken ismi seçimine dikkat etmek, programın başkaları tarafından rahat bir şekilde okunması ve anlaşılması bakımından önemlidir. sever(Kim, tenis) kuralı sever(X, tenis) kuralına tercih edilir. Çünkü Sahis X’e göre daha fazla anlamlıdır.
2.10.1. Prolog’da Değişkenlerin Değer Alması

Diğer programlama dillerinde, değişkenlerin değer almalarına imkan tanıyan atama ifadeleri Prolog’da yoktur. Prolog’u diğer programlama dillerinden ayıran en önemli özelliklerden biri de budur. Prologdaki değişkenler almaları gereken değerleri atamayla değil, gerçekler veya kurallardaki sabitlere eşleştirilirken alırlar.
Bir değişken, değer almadığı müddetçe serbest değişken olarak kalır. Fakat herhangi değer aldığı andan itibaren sınırlı hale gelir. Bu sınırlılık bir sorguya cevap almak için gerekli olan süre kadar sınırlı kalır. Bu işlem bittikten sonra değişken yeniden sınırlı hale gelir, program başa döner ve alternatif çözümler arar. Dolayısıyla bir değişkene bir değer vererek bilgi depolanamaz. Değişkenler bilgi depolamak için değil, kalıp-eşleştirme ve işlemenin bir parçası olarak kullanılır.
PREDICATES
nondeterm sever(symbol, symbol)
CLAUSES
sever(oktay, okuma).
sever(yavuz, bilgisayar).
sever(orhan, tavla).
sever(vedat, uyuma).
sever(ismail, yuzme).
sever(ismail, okuma).
Hem okuma hem de yüzmeden kimin hoşlandığı sorusuna cevap aramak için şu sorguyu kullanılır.
GOAL sever(Sahis, okuma), sever(Sahis, yuzme).
Prolog bu kuralı çözmek ve önce sever(Sahis, okuma) kısmının doğru olup olmadığını bulmak için bütün gerçekleri baştan sonra kadar inceler. Çözüm bulunmadan önce Sahis değişkeninin değeri yoktur, yani serbesttir. Öte yandan okuma kısmı bilinmektedir. İlk sever(oktay, okuma) gerçeğindeki okuma kısmı sorguya uyduğu için Sahis ‘oktay’ değerini alır. Prolog aynı zamanda aşağıya doğru nereye kadar tarama yaptığını göstermek için kuralın başıyla eşleşen ilk noktaya bir ‘pointer’ koymaktadır.
Sorgunun ilk kısmı doğrulandıktan sonra ikinci kısmının da doğrulanması gerekir. Yani yüzmeden hoşlanan kişinin de bulunması gerekir. Sahis değişkeni ‘oktay’ değeri aldığı için artık sever(oktay, yuzme) gerçeğinin doğru olup olmadığı araştırılır. Gerçekler incelenirse, ‘oktay’ isimli şahsın yüzmeden hoşlanmadığı görülür. Bu durumda Prolog Sahis değişkenine atadığı ‘oktay’ değerini etkisiz hale getirir ve Sahis yeniden serbest hale gelir. Kuralın ilk kısmını doğrulayan gerçeği bulmak için Prolog bu kez kuralların başından değil, gerçekler listesine daha önce yerleştirmiş olduğu pointer’den aşağıya kadar doğru taramaya başlar. İlk gerçek gereken şartları sağlayamadığı için artık dikkate alınmaz. Bu işleme Geriye İz Sürme denir.
Yapılan taramada okumadan hoşlanan kişinin ismail olduğu görülünce Sahis değişkeni bu kez ‘ismail’ değerini alır. Kuralın ikinci kısmının doğrulanması için tarama yapılırsa, yüzme için gereken şartın yine ‘ismail’ ile sağlandığı görülür. Dolayısıyla Prolog’un vereceği cevap şu olur:
Sahis=ismail
1 Solution
2.11. Anonim Değişkenler

Anonim değişkenler, programların gereksiz bilgi ve satırlarla karmaşık hale gelmelerini engeller. Böylece bir sorgulamadan beklenilen bilgileri alabilir ve ihtiyaç olmayan değerler iptal edilmiş olur. Prolog’da anonim değişkenler ‘_’ ile gösterilir.
Aşağıdaki örnekte anonim değişkenin kullanımı verilmiştir:
PREDICATES
erkek(symbol)
bayan(symbol)
nondeterm ebeveyn(symbol, symbol)
CLAUSES
erkek(selahattin).
erkek(cihat).
bayan(sacide).
bayan(sezen).
ebeveyn(selehattin, cihat).
ebeveyn(sacide, cihat).
ebeveyn(selehattin, sezen).
GOAL ebeveyn(Ebeveyn,_).
Diğer değişkenlerin yerine kullanılabilen anonim değişkenlerin, normal değişkenlerden tek farkları şudur: anonim değişkenler hiçbir zaman bir değere eşitlenemezler.
 

arago_W&B

Üye
1 Mar 2008
139
3
Yukarıdaki örnek yazdıktan sonra GOAL ebeveyn(Ebeveyn,_) sorgusu çalıştırılarak, ebeveyn olan kişilerin isimleri öğrenilebilir. Çocukların isimleri istenmediği için isimlerinin yerine anonim değişken kullanılmıştır.
Programın sonucunda şu sonuç görüntülenir:
Ebeveyn=selehattin /*Cihat’ın ebeveyni */
Ebeveyn=sacide /* Cihat’ın ebeveyni*/
Ebeveyn=selehattin /* Sezen’in ebeveyni*/
2 solutions
Tanımlanan değişken anonim olduğu için, alınacak cevabın ikinci argümanla bağlantısı olmayacaktır. Anonim değişkenler, gerçeklerin tanımlanmasında da kullanılabilir.
vardir(_,televizyon).
yemek_yer(_).
İfadeleri konuşma dilinde “Herkesin televizyonu var” ve “Herkes yemek yer” olarak çevrilebilir.
2.12. Hedefler (Sorgular)

Şimdiye kadar Prolog’a soru sormak anlamında kullanılan sorgulama kelimesinin yerine bu andan itibaren Hedef(Goal) kelimesi kullanılacaktır. Sorgulamaları hedef olarak tanımlamak daha anlamlıdır, çünkü Prolog’a bir sorgu yöneltmekle, ona yerine getirilmesi gereken bir hedef verilmiş olur.
Hedefler sever(ismail, yuzme) gibi basit olabileceği gibi sever(Sahis, okuma), sever(Sahis, yuzme) gibi daha karmaşık da olabilir. Birden fazla parçadan oluşan hedefe Birleşik Hedef, her bir parçaya da alt hedef denir.
2.12.1. Birleşik Hedefler: Bağlaçlar ve Ayraçlar
Birleşik bir hedefin çözümünü bulmak için her iki alt hedefin doğru olması gerekir. Bu durumda, iki alt hedef arasında (ve) anlamına gelen ‘,’ kullanılır. Fakat istenilen durumlarda alt hedeflerden sadece birinin doğru olması şartı da aranabilir. Bu durumda alt hedefler arasında (veya) anlamına gelen ‘;’ kullanılması gerekir. Bu duruma Ayırma işlemi denilmektedir.
Şimdi bu durumu gösteren bir örnek inceleyelim:
PREDICATES
nondeterm araba(symbol,long,integer,symbol,long)
nondeterm kamyon(symbol,long,integer,symbol,long)
nondeterm arac(symbol,long,integer,symbol,long)
CLAUSES
araba(chrysler,130000,3,kirmizi,12000).
araba(ford,90000,4,gri,25000).
araba(datsun,8000,1,kirmizi,30000).
kamyon(ford,80000,6,mavi,8000).
kamyon(datsun,50000,5,sari,20000).
kamyon(toyota,25000,2,siyah,25000).
arac(Marka,Kilometresi,Yas,Renk,Fiyat):-
araba(Marka,Kilometresi,Yas,Renk,Fiyat);
kamyon(Marka,Kilometresi,Yas,Renk,Fiyat).
GOAL araba(Marka, Kilometresi, Kullanim_Suresi, Renk, 25000).
Bu örnekteki hedef, cümleciklerde tarif edilen 25000 dolarlık arabayı bulur. Benzer şekilde; fiyatı 25.000 dolardan daha az olan bir araba var mı? şeklindeki bir soruya cevap bulmak da mümkündür. Bunun için araba(Marka, Kilometresi, Kullanim_Suresi, Renk, Fiyat), Fiyat< 25000 şeklindeki bir sorguyla bu sorunun cevabını bulmak mümkündür. Bu kuralı sorgulandığında, alınacak cevap chrysler olacaktır.
Şimdi ‘fiyatı 25.000 dolardan az olan bir araba veya fiyatı 20.000 dolardan daha az olan bir kamyon var mıdır?’ şeklindeki bir soruya uygun bir hedef yazalım:
araba(Marka, Kilometresi, Kullanim_Suresi, Renk, Fiyat), Fiyat< 25000; kamyon (Marka, Kilometresi, Kullanim_Suresi, Renk, Fiyat), Fiyat< 20000.
Prolog ilk önce fiyatı 25.000 dolardan daha az olan bir araba olup olmadığını araştırır. Sonuç doğru olsun veya olmasın, ikinci alt hedef de araştırılır. Her ikisinden birinin doğru olması durumunda alınacak cevap olumlu olacaktır. Hedefin doğrulanması için birden fazla alt hedefin aynı anda doğru olması gerekmez. Bu tür hedeflere ayrıştırma denilmektedir ve bunun için alt hedefler arasında ‘;’ ayracı kullanılmaktadır.
2.13. Açıklama Satırları

Program yazarken program satırları arasına açıklamalar yazmak, başkalarının da programı okuyup anlamasına imkan tanır. Program içerisine yazılan bu yorum satırları derleyici tarafından dikkate alınmaz. Prolog’da yorum satırları bir kaç satırdan oluşacaksa ‘/*’ ile başlamalı ve ‘*/’ ile bitmelidir. Eğer tek bir satır yorum yazılacaksa ‘%’ işareti kullanılabilir.
/* Program yazarken kullanılan değişkenler, yüklem ve kurallar*/
/*hakkında bilgi vermek için bu tür yorum satırları yazılabilir*/
%Tek satırlık yoruma bir örnek.
/* İç içe /* yorum */ satırı yazmak da mümkündür*/
2.14. Eşleştirme

Prolog’da eşleştirme yapılırken eşlenik yapılar birbiriyle eşleşebilir. ebeveyn(selehattin, X), ebeveyn(sacide, cihat) kuralındaki X değişkeni ‘cihat’ değerini alır ve serbest olan bu değişken artık bağlı hale gelir. Bağlı hale gelen başka bir değişkene atanırsa, diğer değişken de aynı değeri alır.
2.15. Bölüm özeti

  1. Prolog’da bir program gerçekler ve kurallardan oluşan cümleciklerden oluşur.
  • Gerçekler, doğru oldukları kabul edilen ilişkiler ve özelliklerdir.
  • Kurallar bağımlı ilişkiler olup, gerçekler ve ilişkileri kullanarak bilgi elde etmeye yararlar.
2. Gerçeklerin genel yazılış biçimi şöyledir:
ozellik(nesne1, nesne2,..... nesneN)
veya
ilişki(nesne1, nesne2,..... nesneN)
Burada özellik nesnelerin herhangi bir özelliği, ilişki ise nesneler arasındaki herhangi bir ilişkidir. Özellik ve ilişki kelimelerinin her ikisi de Prolog’da aynı anlamda kullanılır.
  1. Bir programda verilen bir ilişki bir veya daha fazla nesne arasındaki ilişkiden ibarettir. sevmek(ahmet, futbol) gerçeğindeki ‘sevmek’ bir ilişkiyi, ahmet ve futbol ise bu ilişkinin nesnelerini temsil eder. solak(hasan) gerçeğinde ‘solak’ bir özelik, hasan ise bir nesnedir.
  2. Kuralların genel yazılma şekli:
Baş:-Gövde
olup, daha açık hali aşağıdaki gibidir.
ilişki(nesne, nesne, ....., nesne) :-
ilişki(nesne, nesne, ..., nesne),
.
.
ilişki(nesne, nesne, ...., nesne).
  1. İlişki ve nesne isimlerinin yazılması bazı kurallara bağlıdır. Nesne ve ilişki isimleri daima küçük harfle başlar. Bunu takiben istenilen sayıda büyük-küçük harf, rakam, ‘_’ kullanılabilir.
  2. Değişken isimleri daima büyük bir harf veya ‘_’ ile başlar. Bunu takiben istenildiği kadar küçük_büyük harf, rakam vs. kullanılabilir. Değişkenler bir değer almadan önce serbest, değer aldıktan sonra ise bağlı hale gelirler. Bir değişkene değer atayıp bilgi depolamak mümkün değildir. Çünkü bir değişken sadece bir cümlecikte bağımlıdır.
  3. Bir sorgudan sadece belirli bir bilgi alınmak isteniyorsa, anonim değişken (_) kullanılabilir. Anonim değişkene hiçbir zaman değer atanması yapılamaz.
  4. Prolog’a programda verilen gerçeklere göre bir soru sormak Prolog Sistemini Sorgulama olarak adlandırılır ve bu sorguya Hedef denir.
Bileşik bir hedef iki veya daha fazla hedeften oluşur. Bu parçaların her birine alt hedef adı verilir. Bileşik hedefler Bağlaç veya Ayraç şeklinde olabilir.
10. Eşleştirme birbirine denk yapılar arasında gerçekleştirilir. Serbest bir değişken bir sabite veya önceden değer alıp bağımlı hale gelmiş başka bir değişkene atanabilir. Serbest olan iki değişken birbirine atanırsa, birinin alacağı değer otomatik olarak diğerine atanmış olur.
3. VISUAL PROLOG PROGRAMLARININ TEMEL BÖLÜMLERİ

Bir VIP Programı genelde şu dört bölümden oluşur: Clauses (Gerçekler ve Kurallar), Predicates (Yüklemler), Domains (Değişken Tipleri) ve Goals(Hedefler).
3.1. Clauses(Olgular veya Kurallar)

Bu bölüm bir programın kalbi durumundadır. Çünkü programda tanımlı hedefler doğrulanmaya çalışılırken, doğruluğu daha önceden bilinen gerçeklerden yola çıkılır. Gerçek ve gerçekler arasındaki ilişkileri tanımlayan kuralların tanımlandığı yer bu bölümdür. Bir yüklem için tanımlanması gereken bütün clauselar kümesine Procedure denir.
3.2. Predicates (Yüklemler)

Yüklemlerin ve yüklemlerdeki argümanların tiplerinin tanımlandığı yer bu bölümdür. Visual Prolog’da mevcut olan hazır yüklemlerin tanımlanması gerekmez.
3.3. Domains (Değişken Tipleri)

Burada, Visual Prolog’da olmayan tiplerin tanımlanması yapılır.
3.4. Goal (Hedef)

Programdaki sorgular buraya yazılır.
3.5. Yüklem Tanımı

Bir yüklemin genel yazılış biçimi şöyledir:
yuklem_adi(argüman_tip1, argüman_tip2, argüman_tip3,...., argüman_tipN)
Yüklemlerin bitiş parantezinin clauses bölümündeki gibi ‘.’ ile sonlanmadığına dikkat edilmelidir. Yüklem isimleri en fazla 250 karakterten oluşabilir ve herhangi bir harfle başlayabilir. Yüklemler için isim seçilirken küçük veya büyük harfle başlamak önemli değildir. Fakat küçük bir harfle başlayan bir isim seçilmesi önerilir.
 

arago_W&B

Üye
1 Mar 2008
139
3
Çünkü Prolog derleyicilerin çoğu ancak küçük harfle başlayan yüklem isimlerini kabul etmektedir. Kullanılabilecek karakterler şunlardır:
Büyük harfler: A, B, .........., Z
Küçük harfler: a, b, ............, z.
Rakamlar: 0, 1, .................., 9
Alt tire: _.
Geçerli Yüklem İsimleri Geçersiz Yüklem İsimleri​
Olgu [olgu]​
Oynar *gider*​
sahip_olunan_servet Sahiptir/araba​
tahakkuk_fisi bu-ayin-bordrosu​
10_kisilik_sinif <10-kisiden_biri​


Örnekler:
domains
isim=symbol
numara=integer
predicates
ilk_yuklem(isim, numara)


domains
sahis, eylem=symbol
araba, marka, renk=symbol
kilometresi, kullanim_yili, fiyat=integer
predicates
sever(sahis, eylem)
ebeveyn(sahis, sahis)
satin_alabilir(sahis, araba)
araba(marka, kilometresi, kullanim_suresi, renk, fiyat)
yesil(symbol)
derece(symbol, integer)
Yukarıdaki program parçasında yüklem ve argümanların anlamları aşağıda verilmiştir.
  • sever yüklemi iki argüman alır: sahis ve eylem. Bu argümanların her ikisi de değer olarak symbol, yani alfabetik karakterler alabilir.
  • ebeveyn yükleminin iki argümanı da sahis olup, domainde tanımladığı şekliyle symbol tipindedir.
  • satin_alabilir yüklemi tipi symbol olan sahis ve araba argümanlarını almıştır.
  • araba yüklemi 5 adet argüman almıştır. İlk ikisinin tipi symbol, son üçünün ise integer’dır (tamsayı).
  • yesil yüklemi, tipi symbol olan tek bir argüman almıştır. Symbol tipi zaten Visal Prolog’un standart tipleri arasında yer aldığından, ayrıca tanımlamaya gerek yoktur.
  • derece yükleminin argümanları da standart domain’de yer almaktadır.
3.6. Domains (Tip tanımları) Bölümü

Domain kısmında argümanların tipleri tanımlanır. Bir argüman alfabetik, nümerik veya her ikisinden oluşan karakterleri değer olarak alabilir. Domain kısmı, birbirinin aynısı gibi görünebilecek verilere farklı isimler vermemize imkan tanır. VIP programlarında ilişki veya gerçeklerde tanımlanmış olan nesneler (yüklemdeki argümanlar) domainlere aittir. Bu tipler standart olarak tanımlı olabileceği gibi, kullanıcı tarafından sonradan da tanımlanabilir.
Domain kısmı son derece faydalı iki görev icra eder. Birincisi, yüklemlerde tanımlanan argümanların tipleri VIP’de standart olarak tanımlamış olan symbol, tamsayı vs. domainleri olsalar bile, argümanlara farklı anlamlı isimler vermemize imkan tanır. İkincisi, standart domainler tarafından tanımlanmamış veri yapılarını tanımlanmasına imkan sağlar.
Ayrıca, yüklemdeki argümanların net olarak anlatılabilmesi için farklı domainler olarak tanımlanması da faydalıdır.
Örnekler:
  1. Aşağıdaki tabii dil cümlesinin VIP’de karşılığını yazıp, özel domain tanımı aşağıdaki şekilde yapılır.
Hasan, 28 yaşında bir erkektir.
Eğer özel olarak domain tanımlanmazsa, yani VIP’deki standart tipler kullanılırsa yukarıdaki cümle şöyle yazılabilir:
sahis(symbol, symbol, integer)
Bu yüklem ve argümanlar doğru biçimde tanımlandığı için çalışır. Fakat sahis yüklemi içinde tanımlanan üç argümanın neye işaret ettiğini hatırlamak zor olabilir.
Bunun yerine:
domains
isim, cinsiyet = symbol
yas = integer
predicates
sahis(isim, cinsiyet, yas)
şeklinde üç ayrı domain tanımlanırsa sahis argümanındaki isim, cinsiyet ve yas argümanlarının anlamı her zaman için barizdir. Bu tanımlamanın bir faydası da argüman tipleri arasında olabilecek tip eşleştirme hatalarını önlemektir.
Özel domainler, argümanların anlamını çok daha iyi ifade ettikleri halde, bütün argümanlar için özel domain kullanmak gerekmez. Bir argüman için belli bir tip tanımlanması yapıldıktan sonra, bu argüman, tipi aynı olan bir başka argümanla hiçbir şekilde karıştırılmaz. Örneğin isim ve cinsiyet argümanlarının her ikisinin de tipi symbol olmasına rağmen birbiriyle karıştırılmazlar. Fakat kullanıcının tanımladığı argümanların hepsi önceden tanımlanmış argümanlarla karıştırılabilir.
Aşağıdaki örnek, çalıştırıldığı zaman bir tip hatası verir.
DOMAINS
carpma, toplam = integer
PREDICATES
toplama_yap(toplam, toplam, toplam)
carpma_yap(carpma, carpma, carpma)
CLAUSES
toplama_yap(X, Y, Toplam):-
Toplam=X+Y.
carpma_yap(X, Y, Carpma):-
Carpma=X*Y.
GOAL toplama_yap(32, 54, Toplam).
Buradaki GOAL toplama_yap(32, 54, Toplam) doğru çalışır ve
Toplam=86
1 Solution
cevabı alınır. Carpma_yap fonksiyonu için 35 ve 25 değerlerleri kullanılırsa,
Carpma=875
1 Solution
sonucu alnır.
31 ve 17 sayılarının çarpımını bulup, elde edilen sayıyı kendisiyle toplayıp Cevap argümanının değeri aşağıdaki şekilde bulunur.
carpma_yap(31, 17, Toplam), toplama_yap(Toplam, Toplam, Cevap) şeklinde bir hedef yazılabilir. Bu hedefe göre, bulunacak sonucun
Toplam=527 (31*17), Cevap=1054 (527+527)
olması gerekirken, VIP derleyici bir hata mesajı verir. Çünkü carpma_yap fonksiyonundaki Toplam argümanı 527 değerini aldıktan sonra bu değeri ikinci yüklem olan toplama_yap’taki ilk iki argümana taşımaya çalışır. Her iki argüman da tamsayı tipinde olmasına rağmen farklı isimlerde olduklarından, birbirleriyle eşleştirilemezler ve neticede hata mesajı görüntülenir. Bu yüzden bir cümledeki fonksiyonda tanımlanan değişken birden fazla fonksiyonda kullanılacaksa, her fonksiyonda aynı şekilde tanımlanmalıdır.
Örnek:
DOMAINS
marka, renk = symbol
yas=byte
fiyat, yol=ulong
PREDICATES
nondeterm araba(marka, yol, yas, renk, fiyat)
CLAUSES
araba(chrysler,130000,3,kirmizi,12000).
araba(ford,90000,4,gri,25000).
araba(datsun,8000,1,siyah,30000).
GOAL araba(renault, 13, 40000, kirmizi,12000).
GOAL araba(ford, 90000, gri, 4, 25000).
GOAL araba(1, kirmizi, 30000, 80000, datsun).
Burada araba yükleminin 5 argümanı mevcuttur. Yas argümanı byte tipinde olduğu için alabileceği değer 8 bitlik ve 0-255 arasında değişen pozitif bir sayıdır. Aynı şekilde yol ve fiyat tipleri ulong (uzun tamsayı) olup 32-bit pozitif tamsayı değerleri alır. Son olarak marka ve renk tipleri symbol tipindedir. Yukarıdaki sorguları tek tek deneyince her birinin ayrı bir tip hatasına neden olduğu görülecektir. GOAL araba(renault, 13, 40000, kirmizi, 12000) sorgusunda byte tipinde olması gereken yas argümanı 40000 değerini almıştır. Bunun 0-255 arasında olması gerekir. İkinci sorguda yas ve renk argümanlarının değerleri yer değiştirmiştir. Bu nedenle yine hataya neden olur.
3.7. Goal Bölümü

Goal bölümünün bir kuralın yapısından sadece iki farkı vardır.
  1. Goal kelimesinden sonra ‘if’ anlamındaki ‘:-‘ operatörü kullanılamaz.
  2. Program çalışırken VIP ilk önce GOAL satırını çalıştırır.
3.8. Deklarasyon ve Kurallara Ayrıntılı Bakış

Bir yüklemdeki argümanların tiplerini tanımlarken, VIP’de hazır bulunan standart tipler kullanılabilir. Bu tiplerin domains kısmında, ayrıca tanımlanması gerekmez. Aşağıdaki tabloda hazır olarak bulunan tipler verilmiştir (Tablo 1).

Tablo 3.1: Visual Prolog’da Tipler ve Alabilecekleri değerler.

Tip

Kullanıldığı Yer

Değer Aralığı

short
Bütün Platformlar
16 Bit
-32768....+32767
Ushort
Bütün Platformlar
16 Bit
0...65535
Long
Bütün platformlar
32 bit
-2147483648.........+2147483647
Ulong
Bütün platformlar
32 bit
0...4294967295
İnteger (Bilgisayar ve Mimariye bağlı olarak - veya + değer alabilir)
16 Bit Platformlar
32 Bit platformlar
16 Bit
32 Bit
-32768....+32767
-2147483648........+2147483647
Unsigned (Bilgisayar ve mimariye bağlı olarak -/+ değer alabilir)
16 Bit Platformlar
32 Bit platformlar
16 Bit
32 Bit
0...65535
0...4294967295
byte
Bütün platformlar
8 bit
0-255
Word
Bütün platformlar
16 bit
0...65535
Dword
Bütün platformlar
32 bit
0...4294967295
 

arago_W&B

Üye
1 Mar 2008
139
3
Her değişken tipi verilen aralıkta bulunan bir değeri alabilir. Integer ve unsigned tipleri, değişkenlerin tanımlandığı bilgisayar veya sistemlere göre değişen aralıktaki değerleri alırlar.
Domain tanımı yapılırken signed veya unsigned kelimeleri byte, word ve dword domainleri ile birlikte kullanılabilirler.
Domains
i8 = signed byte
tanımı normalde unsigned olan ve bu yüzden 0-255 aralığından değer alan byte yerine -128...+127 değerleri arasında değer alan bir tip haline gelir.
3.8.1. Char

İşaretsiz bir byte olarak kullanılır. Örnek: ‘A’, ‘b’...
3.8.2. Real

+/- DDDD.DDDD şeklinde olan 8 bitlik bir değişken. (1*10-307-1*10+308)
3.8.3. String

255 karakter uzunluğunda olabilen bu tipin iki formatı vardır.
  1. İlki küçük harf olmak üzere harf, sayı veya altçizgiden oluşur.
  2. Çift tırnak arasına alınmış karakterlerden oluşur. Örnek
Örnekler: Adı_soyadı, “Müşterinin Adı”, “Fox Ltd.”
3.8.4. Symbol

Formatı string’ler ile aynıdır.
Symbol ve string değişkenler birbirinin aynısı olmakla beraber, VIP bunları farklı şekillerde depolar. Symbol tipleri bir tabloda saklanır. Adresleri ise nesneleri temsil edecek şekilde saklanır. Böylece eşleştirme işleminde hızlı kullanılırlar. Fakat karşılaştırmalarda String tipler karakter bazında eşleştirilir.
3.9. Yüklemlerdeki Argümanların Yazılması

Predicates bölümündeki bir argümanın tipini tanımlamaya, argüman tipi tanımlama denilmektedir.
Hasan, 28 yaşında olan bir erkektir = sahis(hasan, erkek, 28).
Sahis bu argümanlarla birlikte kullanan bir yüklem olarak tanımlamak için aşağıdaki satırın predicates bölümünde yazılması gerekir.
sahis(symbol, symbol, unsigned)
Görüldüğü gibi her üç argüman da standart tipte tanımlanmıştır. Yani, program içerisinde her ne zaman sahis yüklemi geçerse, bu yüklemi sadece 3 argümanla birlikte kullanılabilir. Bunların ilk ikisi symbol, üçüncüsü ise unsigned tipinde bir integer olmalıdır.
Alfabedeki bir harfin yerini belirleyen alfabedeki_yer(Harf, Yer) şeklinde bir ilişkiyi incelendiğinde, Harf ve Yer argümanlarının her ikisi de değişken olarak tanımlandığı görülür. Böylece Harf=a ise Yer=1, Harf=b ise Yer=2 vs. şeklinde devam eder. Bu durum kısaca şöyle ifade edilebilir.
alfabedeki_yer(Bir_harf, N).
Bunun için yazılması gereken olgular:
alfabedeki_yer(‘a’, 1).
alfabedeki_yer(‘b’, 2).
alfabedeki_yer(‘c’, 3).
...........
alfabedeki_yer(‘z’, 29.)
şeklinde olmalıdır.
PREDICATES
alfabedeki_yer(char, integer)
CLAUSES
alfabedeki_yer(‘a’, 1).
alfabedeki_yer(‘b’, 2).
alfabedeki_yer(‘c’, 3).
GOAL alfabedeki_yer(‘c’, Nerede).
Program çalıştırıldığında ‘c’ harfinin yerini veren Nerede değişkeni 3 değerini alır.
Örnek:
DOMAINS
adi_soyadi, tel_no = symbol
PREDICATES
nondeterm telefon_numarasi(adi_soyadi, tel_no)
CLAUSES
telefon_numarasi("Orhan AYDIN", "255 45 47").
telefon_numarasi("Arif GÜREL", "3134578").
telefon_numarasi("Husamettin BULUT", "3145869").
telefon_numarasi("Kasim YENIGÜN", "3174152").
Bu program, aşağıdaki sorgularla veya yenileri ilave edilerek çalıştırılabilir.
GOAL telefon_numarasi(Kimin_Telefonu, "3145869").
GOAL telefon_numarasi("Orhan AYDIN", Telefon_Numarasi).
GOAL telefon_numarasi(Telefon_Sahibinin_Adi, Telefon_Numarasi).
Örnek: Ekrandan girilen bir karakterin harf olup olmadığını kontrol eden bir program yazınız. (Not: char tipi sadece bir tek karakteri tanımlar)
REDICATES
nondeterm aranan_harf(char)
CLAUSES
aranan_harf(Harf):-
‘a’<=Harf,
Harf<=’z’.
aranan_harf(Harf):-
‘A’<=Harf,
Harf<=’Z’.
GOAL
aranan_harf(‘x’).
aranan_harf(‘2’).
aranan_harf(“Merhaba”).
aranan_harf(‘a’).
aranan_harf(x).
Yukarıdaki program, verilen bir karakterin alfabenin bir harfi olup olmadığını test etmektedir. Yazılan sorguları kullanarak elde edilen sonuçları inceleyiniz. Bazı şıklarda neden hata verdiğini bulmaya çalışınız.
Predicate bölümünde aynı isimde birden fazla yüklem tanımlanabilir. Fakat bunların argümanlarının farklı sayıda olması gerekir. Predicates ve Clauses bölümlerinde aynı isimde olanların birlikte gruplanmaları gerekir. Bu yüklemler, tamamen farklıymış gibi işlem görürler.
Örnek:
DOMAINS
sahis=symbol
PREDICATES
baba(sahis) %Buradaki şahıs bir babadır.
baba(sahis, sahis) %Buradaki birinci kişi ikinci kişinin babasıdır.
CLAUSES
baba(Insan):-,
baba(Insan, _).
baba(ahmet, mehmet).
baba(omer, yavuz).
3.10. Kuralların Yazım Biçimi

VIP’de kurallar, Baş ve Gövde olmak üzere iki kısımdan meydana gelir.
Genel Biçim:
Baş:- <alt hedef1>, <alt hedef2>,......, <alt hedefN>.
Alt hedefler biribirinden ‘,’ ile ayrılır ve sonuncusu nokta ile biter. Alt hedeflerin her biri ayrı bir yüklem çağırır. Alt hedefin doğru olup olmadığı kontrol edilir. Sonuç ne olursa olsun, bu işlem bütün alt hedeflere uygulanır. Alt hedeflerin tamamının olumlu netice vermesiyle beraber o kuralın doğruluğu ispatlanmış olur. Sadece bir alt hedef bile yanlış olursa, bütün kural yanlış olur.
3.11. Prolog ve Diğer Dillerdeki ‘if’ Komutunun Karşılaştırılması

VIP’de baş ve gövde kısmını ayıran ‘:-‘ sembolü if anlamına gelir. Örneğin Pascal’daki if komutu, öncelikle if komutundan sonra gelen ifadenin doğru olup olmadığını kontrol eder. Eğer ifade doğrulanırsa, komut then ifadesinden sonraya geçer geçer.
Yani if x>10 then writeln(“Bu işlem tamam”);
satırında öncelikle x değişkeninin 10’dan büyük olup olmadığı kontrol edilir. Eğer sonuç doğru ise ‘Bu işlem tamam’ satırı görüntülenir. Aksi takdirde program bir alt satırdan itibaren çalışmaya devam eder. Bu tip ifadeye if/then şartlı denir. VIP ise bunun tam tersi olan bir sistem uygular. Öncelikle gövdedeki alt hedeflerin doğru olup olmadığına bakılır. Tamamı olumlu sonuç verirse, kuralın gövde kısmının doğruluğu ispatlanmış olur. Bu ise VIP’da then/if şartının geçerli olduğunu gösterir.
3.12. Otomatik Tip Dönüştürmeler

VIP’de iki değişken karşılaştırıldığında her ikisinin de aynı tipte olması her zaman gerekmez. Değişkenler bazen başka tiplerdeki sabit değişkenlere de atanabilir. Çünkü VIP aşağıdaki tipler arasında otomatik olarak tip dönüştürmesini yapar.
  • string ve symbol
  • Bütün integral tipler ve reel değişkenler. Bir karakter sayısal bir değere dönüştürülürken, bu karakterin karşılığı, sayının ASCII tablosundaki karşılığı olur.
Örneğin string tipindeki bir agüman symbol tipi ile uyumludur. Benzer şekilde integer olarak tanımlı bir tip real, char, word etc. Tipleriyle uyumludur. Bu tür tip değişikliği şu kolaylıkları sağlar:
  • string tipiyle tanımlı bir yüklem symbol tipindeki bir argümanla çağrılabilir.
  • real tipiyle tanımlı bir yüklem integer tipindeki bir argümanla çağrılabilir.
  • char tipiyle tanımlı bir yüklem integer tipindeki bir argümanla çağrılabilir.
  • Alfabetik karakterler ASCII değerleri bilinmeden de rahatlıkla kullanılabilir.
 

arago_W&B

Üye
1 Mar 2008
139
3
Argümanlar, tanımlı olduklarının dışında bir tipe dönüşürken ne gibi kuralların etkili olduğu, sonuçta ortaya çıkan argümanının hangi tipte olacağı konusu ileride incelenecektir.
3.13. Bir Programın Diğer Bölümleri

Şimdiye kadar VIP’daki clauses, predicates, domains ve goals bölümleri incelenmiş ve bol miktarda örnek verilmiştir. Şimdi database, constants ve global bölümlerine kısa bir giriş yapılacaktır.
3.13.1. Database Bölümü

Bir VIP programının gerçekler ve kurallardan oluştuğu bilinmektedir. Program çalışırken bazen kullanılan gerçek ve kuralları değiştirmek, güncellemek, ilave yapmak veya çıkarmak gerekebilir. Böyle bir durumda gerçekler, dinamik bir dahili veritabanı oluşturur. Program çalışırken değiştirilebilecek gerçeklerin tanımlı olduğu bölüme database bölümü denilmektedir.
3.13.2. Constants Bölümü

Diğer dillerde olduğu gibi VIP’de de sabit değişkenler kullanılabilir. Bu değişkenler constants bölümünde tanımlanır. Her bir satıra sadece tek bir sabit yazılabilir.
constants
yuz=(10*(10-1)+10)
pi=3.14159265
maas_katsayisi=4
mavi=5
Program derlenmeden önce her sabit değişkenin karşısındaki string olduğu gibi atanır. Örnek:
A=yuz*34, bekle(A)
şeklindeki A değişkenine yuz sabiti yerine 100 değil, yuz sabit değişkeninde tanımlı şekliyle (10*(10-1)+10) değeri atanır.
Sembolik sabitlerin yazımında şu kurallar geçerlidir:
  • Sabit bir değişken kendisini çağıramaz. Yani sayi= 2*sayi/2 yanlıştır.
  • Büyük veya küçük harfle başlayan sabit değişkenler, farklı olarak işlem görmezler. Bu yüzden büyük harfle başlayan sabit bir değişken clause veya goal bölümünde küçük harfle başlatılmalıdır. Böylece büyük harfle başlamaları zorunlu olan normal değişkenlerle karışmazlar. Örnek:
constants
iki=2
goal A=iki, write(A).
  • Bir programda birden fazla constants bölümü olabilir. Fakat programda kullanılmadan önce bu değişkenlerin mutlaka tanımlanmış olmaları gerekir.
  • Tanımlanan sabitler tanımlanan noktadan başlayıp programın sonuna kadar aynı değerde kalırlar. Bir sabit değişken sadece bir kez tanımlanabilir.
3.13.3. Global Bölümü

VIP’de şimdiye kadar tanımladığımız domains, predicates ve clauses bölümleri tamamen lokal idi. Bunları global yapmak için programın en başında global domains, global predicates vs. bölümler oluşturulabilir. Bu konu daha sonra incelenecektir.
3.14. Derleyici Direktifleri

VIP, yazılan bir program parçasının derleme sırasında belirtilen şekilde işlem görmesi için bazı direktiflerin kullanılmasına imkan tanır. Bu seçenekler menüdeki Options/Compiler Directives başlığından ayarlanabilir.
3.14.1. Include Direktifi

Bu direktif daha önce yazılan bir program parçasının veya prosedürün her çağrıldığında aynı program içerisinde tekrar tekrar kullanılmasını sağlar. Bu durum basit bir örnek üzerinde açıklanmaktadır.
İçinde en sık kullanılan tip ve yüklemlerin bulunduğu TEST.PRO isminde bir programın olduğunu varsayalım. Hazırlanan başka bir programda bu program çağırılıp kullanılmak istendiğinde, kullanılan
include “test.pro”
bir derleyici direktifidir. Ana program derlendiği zaman VIP test.pro isimli programı derleyip ana programa ilave eder. Include direktifiyle tanımlanan bir programda da başka bir include satırı bulunabilir ve o da başka bir programı çağırabilir. Fakat bir programda bir dosya sadece bir kez include “dosyaismi.pro” şeklinde kullanılabilir.
3.15. Bölüm Özeti

  1. Bir VIP programının yapısı şu şekildedir:
domains
argüman1,...,argümanN=tip
predicates
yüklem_ismi(argüman1,..., argümanN)
clauses
kurallar ve gerçekler
GOAL
alt_hedef1, alt_hedef2, ........, alt_hedefN
  1. Domains bölümünde kullanılacak değişkenlerin tipleri tanımlanır. VIP’da kullanılabilecek bazı tipler: char, byte, short, ushort, word, integer vs.
  2. Yazılmış olan gerçek ve kuralları inceleyerek doğruluğunun sağlanması istenilen Goal (sorgu), programın içine yazılması gerekir. Bu dahili bir sorgudur. Harici olarak tanımlanacak olan bir sorgu program çalışırken açılan Dialog penceresine yazılır.
  3. Aynı isimde fakat farklı sayıda argüman taşıyan yüklemler tamamen farklı yüklemlermiş gibi işlem görür.
  4. Kurallar Baş:- alt_hedef1, alt_hedef2, ........., alt_hedefN genel şekliyle yazılır. Bir kuralın istenilen sonucu vermesi için alt hedeflerin tamamının doğrulanması gerekir.
  5. Prolog’daki if komutu diğer dillerdeki if komutundan farklıdır. Prolog’da then/if şeklinde tanımlı olan bu komut diğer dillerde if/then şeklinde tanımlıdır.
4. EŞLEŞTİRME VE GERİYE İZ SÜRME

VIP bir alt hedeften gelen bir çağrıyı clauses bölümünde tanımlı bir cümle ile karşılaştırmaya çalışırken belirli bir işlem kullanır. Bu işleme eşleştirme denir. Bir program çalışırken
Goal yazdi(X,Y).
sorgusunun kullanıldığını kabul edilsin. Bu sorgunun doğruluğunu araştırırken, clauses bölümdeki bütün yazdi(X,Y) cümlecikleri eşleştirme işlemi için test edilir. Goal yazdi(X,Y) ifadesindeki X ve Y argümanları, clauses bölümündeki yazdi(...) cümlecikleriden kontrol edilir. Bunun için bütün cümlecikler tek tek incelenir. Sorguyla eşleşen bir cümle bulunduğu zaman cümledeki değer serbest olan değişkene atanır ve böylece cümle ile goal eşleşmiş olur. Bu duruma ‘sorgunun cümle ile eşleşmesi’, bu işleme de eşleştirme denilir.
Örnek
DOMAINS
kitap_adi, yazar = symbol
sayfa_sayisi = unsigned
PREDICATES
kitap(kitap_adi, sayfa_sayisi)
nondeterm yazdi(yazar, kitap_adi)
nondeterm roman(kitap_adi)
CLAUSES
yazdi(eco, "Gülün Adı").
yazdi(tolstoy, "İnsan Ne İle Yaşar").
kitap("İnsan Ne İle Yaşar ", 245).
kitap("Gülün Adı", 760).
roman(Kitap_adi):- yazdi(_, Kitap_adi), kitap(Kitap_adi, Sayfa_sayisi), Sayfa_sayisi> 400.
GOAL yazdi(Yazar, Kitap_adi).
Sorgudaki Yazar ve Kitap_adi değişkenleri serbest değişkenler olduklarından herhangi bir argümana eşitlenebilirler. Dolayısıyla sorgu clauses bölümündeki ilk yazdi cümlesi ile eşleşir. Yani yazdi(Yazar, Kitap_adi) cümleciği yazdi(eco, “Gülün Adı”) olur. Burada Yazar=eco, Kitap_adi=Gülün Adı değerini alır. Aynı işlem bütün alternatif çözümler için tekrar edileceğinden, Yazar ve Kitap_adi değişkenleri sırasıyla tolstoy ve İnsan Ne İle Yaşar değerlerini de alır. Yani sonuçta 2 çözüm bulunur.
GOAL roman(Roman_adi) çağrısının nasıl çalıştığı incelenecektir. Bir çağrının bir olgu veya kuralın baş kısmıyla eşleşip eşleşmediği kontrol edilir. Yani kuralın baş kısmı olan roman(Kitap_adi) kısmıyla eşleşir. Kullanılan olgudaki argümanlar eşleştirilir. X argümanı bağlı olmadığı için herhangi bir argümanla eşleşebilir. Kuralın başı olan roman(Kitap_adi)’ında, Kitap_adi argümanı bağımsız bir değişkendir. Kuralın başıyla sorgu kısmı eşleştirilir. VIP, eşleştirme yapıldıktan sonra alt hedefleri sırasıyla doğrulamaya çalışır.
roman(Kitap_adi):-
yazdi(_, Kitap_adi),
kitap(Kitap_adi, Sayfa),
Sayfa>400.
GOAL roman(Roman_adi) kodunda ilk önce yazdi(_,Kitap_adi) kısmı sorgulanır. Buradaki ilk argüman anonimdir. Dolayısıyla ilk olgudaki eco ve Gülün Adı ‘_’ ve ‘Kitap_adi’ argümanlarıyla eşleşir. Bundan sonra kitap(Kitap_adi,Sayfa_sayisi) cümleciğindeki kitap olgusuna çağrı yapılır. İlk cümlecikteki ‘eco’ ve ‘Gülün Adı’ değerlerini alır. İlk alt hedef doğrulandığı için sonraki adım olarak kitap(Kitap_adi, Sayfa_sayisi) alt hedefine geçilir. Kitap_adi argümanı ‘Gülün Adı’ değerine bağlı hale geldiği için çağrı kitap(“Gülün Adı’, Sayfa_sayisi) şeklinde devam eder. Programın başından başlayan sorgu kitap(“Gülün Adı”, 760) cümleciğinde eşleştirme yapmaz. Çünkü ilk argüman ‘Gülün Adı’ olmuştu. İkinci cümlecik sorguyu doğrular ve Sayfa_sayisi 760 değerini alır. Sayfa_sayisi>400 alt hedef halini alır. 760 değeri 400’den büyük olduğu için alt hedef doğrulanır ve böylece bütün hedef doğrulanmış olur. Sonuçta şu mesaj görüntülenir:
Roman_adi=Gülün Adı
1 Solution
 

arago_W&B

Üye
1 Mar 2008
139
3
4.1. Geriye İz Sürme

Gerçek problemlere çözüm ararken, verilen karar doğrultusunda mantıklı olan bir yol takip eder, yolun sonuca ulaşmaması durumunda alternatif bir yol aranır. Mesela bir labirent oyununda çıkış yolunu ararken sola veya sağa doğru gidilir. Çıkmaz sokağa gelindiğinde geriye döner, başka bir yolu takip eder. Bu yönteme göre devam edilirse, sonunda çıkış noktası bulunur.
VP, geriye iz sürme denilen bu sistemi kullanır. Bir sorgunun doğru olup olmadığı araştırılırken alt hedeflerin herbirinin ayrı ayrı doğrulanmaya çalışılır. VP, doğrulama işlemini yürütürken sorgulanması gereken durumların başlangıç noktasına bir işaret koyar. Sonra bu yolların ilkini dener. Eğer olumlu sonuç alınırsa işleme oradan itibaren devam eder. Sonucun olumsuz çıkması durumunda, işaret konulan yere döner ve ikinci yolu, yani bir sonraki alt hedefi dener. İşte bu ileriye gidiş ve gerektiğinde yine geriye dönüş işlemine Geriye İz Sürme denir.
Örnek
PREDICATES
nondeterm yemeyi_sever(symbol, symbol)
nondeterm yemek(symbol)
yemegin_tadi(symbol, symbol)
CLAUSES
yemeyi_sever(besir,X):-
yemek(X),
yemegin_tadi(X, iyi).
yemegin_tadi(kebap, iyi).
yemegin_tadi(kapuska, kotu).
yemek(kapuska).
yemek(kebap).
GOAL yemeyi_sever(besir, Besirin_Sevdigi_Yemek).
Programda iki olgu kümesi, bir de kural bulunmaktadır. Kural, Bülent’in, tadı güzel olan yemeklerden hoşlandığını söylemektedir. Sorgunun doğrulanması için VP ilk satırdan başlayarak tarama yapar. Hedefe uyan ilk satır yemeyi_sever(bulent, X) kuralının başı olduğu için Besirin_Sevdigi_Yemek argümanı X ile eşleşir. Bu durumda kuralın geri kalan kısmının doğrulanmasına çalışılır. Buradaki ilk alt hedef yemek(X) cümleciğidir. VP alt hedefi doğrulamak için yine programın en başına gider. VP eşleşen bir olgu ararken yemek(kapuska) cümleciğine ulaşır ve burada X değişkeni ‘kapuska’ değerini alır. VIP, buraya geri dönüş işaretini koyar ve alternatif bir çözüm ararken hareket edilecek ilk noktanın başlangıcı belirtilmiş olur.
Bir sonraki hedef, yemegin_tadi(X, iyi) alt hedefi olur. X ‘kapuska’ değerini aldığına göre bu cümle yemegin_tadi(lahana, iyi) şekline dönüşür. Bunun doğrulanması sırasında argümanlar başka bir olguyla eşleşmediği için bu alt hedef olumsuz olur. Dolayısıyla sorgunun bu doğrulanması başarısız olur. İşte bu noktada VP geri dönüş işaretini koyduğu en son noktaya, yani yemek(kapuska) cümleciğine gider. Geri dönüş noktasına gelindiğinde, bu noktadan sonra değer almış olan bütün değişkenler yeniden serbest hale gelirler.
Bu noktadan sonra ilk eşleşme yemek(kebap) olgusu ile olur ve X değişkeni kebap değerini alır. Daha sonraki alt hedef yemegin_tadi(kebap, iyi) olduğundan, programın başından itibaren yapılacak bir taramadan olumlu sonuç alınır. Çünkü yemegin_tadi(kebap, iyi) olgusu önceden tanımlanmıştı. Sonuçta görüntülenecek mesaj şu olur:
Besirin_sevdigi_yemek=kebap
1 Solution
Geriye İz Sürme yöntemiyle sadece tek çözüm değil, mümkün olan bütün çözümler elde edilir.
DOMAINS
aday=symbol
adayin_yasi=integer
PREDICATES
nondeterm oyuncu(aday, adayin_yasi)
CLAUSES
oyuncu(ahmet, 10).
oyuncu(mehmet, 12).
oyuncu(ali, 10).
oyuncu(huseyin, 10).
GOAL oyuncu(Birinci_oyuncu, 10), oyuncu(Ikinci_oyuncu, 10),
Birinci_oyuncu<>Ikinci_oyuncu.
VP’den yaşları 10 olan çocuklar arasında düzenlenecek bir masa tenisi turnuvası için muhtemel ikili rakip listesi istensin. Eşleştirme sırasında yaşları 10 olan, fakat kendileriyle eşleşmeyecek ikili gruplar istensin. Geriye İz Sürme yönteminin nasıl çalıştığını görmek için VP’nin takip edeceği prosedürü adım adım yazarsak:
  1. VP ilk önce sorgunun oyuncu(Birinci_oyuncu, 10) alt hedefini doğrulamaya çalışır. Bu hedef oyuncu(ahmet, 10) cümleciğiyle sağlanmış olur. VP hemen ikinci alt hedefi doğrulamaya çalışır. (Bu sırada programın en başına dönüş yapılır) oyuncu(İkinci_oyuncu, 10) alt hedefini sağlamaya çalışırken yine 10 yaş şartını birinci cümlecik sağlar. Dolayısıyla İkinci_oyuncu argümanı da ‘ahmet’ değerini alır. Her iki alt hedef sağlandıktan sonra şimdi üçüncü alt hedef sağlanmaya çalışılır. Yani Birinci_oyuncu<>İkinci_oyuncu (Birinci ve ikinci oyuncu aynı kişi olmayacak)
  1. Oyuncuların her ikisi de ahmet olarak eşleştiği için bu hedef sağlanamaz, dolayısıyla sorgu başarısız olur. VP’nin Geriye İz Sürme mekanizması yeniden bir önceki alt hedefi, yani ikinci alt hedefi sağlamaya yönelir. Bu kez ikinci_oyuncu argümanı ali değerini alır.
  2. Üçüncü alt hedef sağlanmış olur. Çünkü ahmet ve ali, yaşları 10 olan farklı kişilerdir. Bütün alt hedefler sağlandığından sorgunun tamamı başarılmış olur. Sonuçta oluşan ilk ikili
Birinci_oyuncu= ahmet, İkinci_oyuncu=ali
olarak bulunmuş olur.
  1. VP’nin sadece bir çözüm değil, mümkün olan bütün çözümleri bulur. Bu yüzden 3. alt hedef sağlandıktan sonra başka çözüm olup olmadığını bulmak için bütün alternatifler tükeninceye kadar ikinci alt hedefi sorgulanır. Bu kez ikinci_oyuncu olarak Hüseyin seçilir. Ahmet ve Hüseyin 3. şartı da sağladığı için ikinci grup ahmet ve hüseyin’den oluşur.
  2. Peki başka çözüm var mı? VP bunu bulmak için yine ikinci alt hedefe dönüş yapar. Görüldüğü gibi son oyuncu olan Hüseyin ile bu şanş tükenmiştir. İşte bu noktada Geriye İz Sürme yine ilk alt hedefe döner. İkinci eşleşme oyuncu(ali, 10) cümlesinde olur. İkinci oyuncu Hüseyin ile eşleşir. En son alt hedef de sağlandığı için bu kez ali=hüseyin ikilisi oluşturulur.
  3. Başka çözüm için VP 2. alt hedefe döner. VP ikinci kez hüseyin ismiyle eşleşme yapar. Fakat kişi aynı olduğundan sonuç alınamaz. Geriye İz Sürme yöntemiyle bütün seçeneklerin sırasıyla denenmesi sonucunda şu tablo ortaya çıkar.
Birinci_oyuncu=ahmet, İkinci_oyuncu=ali
Birinci_oyuncu=ahmet, İkinci_oyuncu=hüseyin
Birinci_oyuncu=ali, İkinci_oyuncu=ahmet
Birinci_oyuncu=ali, İkinci_oyuncu=hüseyin
Birinci_oyuncu=hüseyin, İkinci_oyuncu=ahmet
Birinci_oyuncu=hüseyin, İkinci_oyuncu=ali
6 Solutions
Bulunan sonuçların bazıları, isimlerin sadece yer değiştirilmesinden oluşmuş aynı ikili gruplardır. Bunu engellemek mümkündür.
(Not: Aynı program ile yaşları 10 ve 12 olan ikili grupları bulunuz)
4.2. Geriye İz Sürme Mekanizmasının Ayrıntıları

Aşağıdaki programa bakarak Geriye İz Sürme işlemenin nasıl işlediğini anlamaya çalışalım.
DOMAINS
isim, sey= symbol
PREDICATES
sever(isim, sey)
okur(isim)
merakli(isim)
CLAUSES
sever(ahmet, limonata):-!.
sever(murat, yuzme):-!.
sever(murat, kitap):-!.
sever(murat, basketbol):-!.
sever(Z,kitap):-
okur(Z), merakli(Z).
okur(ahmet).
merakli(ahmet).
GOAL sever(X, limonata), sever(X, kitap).
VP hedefi değerlendirirken, doğrulanan ve doğrulanamayan alt hedefleri belirler. Yukarıdaki programa aşağıdaki hedefi göz önüne alarak bakalım. Hedef aşağıdaki gibi bir ağaç dalı şeklinde gösterilebilir. Doğrulanan alt hedefi altı çizili halde, bununla eşleşen cümleciği de bunun hemen altına yazalım.
sever(X,limonata)
Sever(X,kitap)
4.2.1. Geriye İz Sürmenin 4 Temel Prensibi

Yukarıdaki örnekte, hedefin gerçekleştirilmesi için doğrulanması gereken iki alt hedef vardır. Bunun için VP dört temel prensibe göre çalışır:
  1. Bütün alt hedefler, ilkinden başlanmak üzere, birer birer doğrulanmalıdır. Bir cümleciğin doğrulanması için hangi alt hedefin kullanılacağına ikinci kurala göre karar verilir.
  2. Yüklem cümlecikleri (fonksiyonlar) programdaki sırasıyla, yukarıdan aşağıya göre test edilirler. Buna göre yukarıdaki program çalışırken ‘sever’ yüklemini sağlayan sever(ahmet, limonata) cümleciğiyle doğrulanır. Dolayısıyla sever(X, limonata) alt hedefindeki X argümanı ‘ahmet’ değerini alır. Daha sonra ikinci alt hedef doğrulanmaya çalışılır. Burada bağlı hale gelen X=ahmet argümanı kullanılır. Fakat sever(ahmet, limonata) alt hedefi sever(ahmet, kitap) alt hedefine eşitlenemez, çünkü limonata ve kitap aynı değildir. Bütün cümleciklerin sırayla deneneceği için bir sonraki cümlecik sever(murat, kitap) olacaktır. Fakat X daha önce ‘ahmet’ değerini aldığı için bu şık da başarısız olur. Bu yüzden bir sonraki sever cümleciğinin sağlanması gerekir.
sever(Z,kitap):-okur(Z), merakli(Z).
Z argümanı bir değişkendir ve X değişkeni ile eşleşebilir. Zaten ‘kitap’ argümanları da eşleşir. Dolayısıyla hedef, kuralın baş kısmıyla eşleşmiş olur.
Bir alt hedef bir kuralın baş kısmıyla eşleştiği zaman, kuralın gövde kısmının doğrulanması sağlanmalıdır. Böylece kuralın gövdesi doğrulanması gereken bir alt hedefler kümesi oluşturur.
Şimdi yeniden örneğe dönelim.
sever(X,limonata) sever(X,kitap)
okur(Z) merakli(Z)
okur(Z) ve merakli(Z) alt hedeflerinin doğrulanması gerekir. Burada Z değişkeninin ‘ahmet’ değerini aldığı söylenmişti. Şimdi ise her iki alt hedefi de sağlayan sorgulama başlayacaktır. Sonuçta elde edilecek ağaç:
sever(X,wine)sever(X,kitap)
sever(ahmet,wine) sever(Z,kitap)
okur(Z)merakli(Z)
okur(ahmet)merakli(ahmet)
  1. Hedef ağacının her bir dalını sağlayan bir gerçek bulunduğu zaman hedef sağlanmış olur.
Sonuçta
X=ahmet
1 Solution
cevabı görüntülenir. Harici bir hedef doğrulandıktan sonra VP’nin, eğer varsa, bütün alternatifleri bulmak için çalışacağı söylenmişti. Bir alt hedef başarısız olursa, VP yeniden bir önceki alt hedefe döner. Bu alt hedefi, biraz önce başarısız hale gelen alt hedefi de doğrulayacak bir cümlecik ile doğrulamaya çalışır.
VP bir alt hedefi sağlamak için sorgulamaya yüklemi tanımlayan ilk cümlecikten başlar. Bu sırada aşağıdaki durumlardan biri meydana gelebilir:
  1. İlk cümlecik verilen yüklemle eşleşir. Bu durumda;
  1. Alt hedefi doğrulama ihtimali olan başka bir cümlecik varsa, Geriye İz Sürme işleminde kullanılmak üzere bu cümleciğin yanına bir işaret konur.
  2. Alt hedefteki bütün serbest değişkenler cümlecikteki değerleri alır ve bağlı hale gelirler.
 

arago_W&B

Üye
1 Mar 2008
139
3
  1. Eğer eşleşen cümlecik bir kuralın baş tarafı ise, hemen kuralın gövde kısmı değerlendirilir. Bu durumda gövdedeki bütün alt hedeflerin doğrulanması gerekir.
  1. Eşleşen herhangi bir cümlecik bulunmaz ve sorgu başarısız hale gelir. VP bir önceki alt hedefi doğrulamak için geriye iz sürer. En son geriye dönüş noktasına geldiğinde, VP geriye dönüş noktasından sonra değer almış bütün değişkenleri serbest hale getirir. Daha sonra alt hedefi yeniden doğrulamaya çalışır.
Tarama, programın başından başlar. Geriye İz Sürme işlemi, daha önce yerleştirilen geriye dönüş noktasından itibaren başlar. Sorgu burada da başarısız olursa, geriye iz sürme işlemi tekrar edilir. Bütün alt hedef ve cümlecikler için geriye dönüş işlemi tamamlandığında sonuç elde edilemezse, hedef başarısız olur.
Geriye dönüş işlemi için başka bir örnek.
Örnek:
PREDICATES
nondeterm tur(symbol, symbol)
nondeterm canli(symbol, symbol)
yasar(symbol, symbol)
nondeterm yuzebilir(symbol)
CLAUSES
tur(tirnakli, hayvan).
tur(balik, hayvan)
canli(zebra, tirnakli).
canli(alabalik, balik).
canli(kopekbaligi, balik).
yasar(zebra, karada).
yasar(kurbaga, karada).
yasar(kurbaga, suda).
yasar(kopekbaligi, suda).
yuzebilir(Y):-
tur(X, hayvan),
canli(Y,X),
yasar(Y, suda).
GOAL yuzebilir(Ne), write(“Bir ",Ne," yüzebilir\n").
Program yazılıp çalıştırıldığında ilk olarak GOAL bölümü sağlanmaya çalışılır. Şimdi yapılacak işlemleri adım adım yazalım:
  1. yuzebilir yüklemi, ‘Ne’ serbest değişkeni ile çağrılır. Eşleşme olup olmadığını bulmak için program tarandığında ‘Ne’ argümanı ‘Y’ değerini alır.
  2. Hemen sonra hedefin gövde kısmına geçersek tur(X,hayvan) alt hedefinin doğrulanması gerekir. Programın başından itibaren yapılacak bir taramada tur(tirnakli, hayvan) cümleciği bu alt hedefi sağlar. Böylece X=tirnakli değerini alır.
  3. Burada tur(X,hayvan) alt hedefini sağlayabilecek birden fazla alternatif olduğu için, tur(tirnakli,hayvan) cümleciğinin yanına Geriye İz Sürme işareti konur.
  4. X değişkeni ‘tirnakli’ değerini alınca birinci alt hedef doğrulanmış olur. Bu kez ikinci alt hedef yani canli(Y, X) doğrulanmaya çalışılır. Bu hedef ise canli(Y, tirnakli) olarak sağlanır. canli(zebra, tirnakli) cümleciği ikinci alt hedefi sağlar ve Y değişkeni ‘zebra’ değerini alır ve bu hedefi sağlayan başka cümlecikler de mevcut olduğundan, VP bu cümleciğin yanına da bir Geriye İz Sürme işareti koyar.
  5. Şimdi X=tirnakli ve Y=zebra olacak şekilde en son alt hedefin doğrulanması gerekir. yasar(Y, suda) alt hedefinin sağlanması için yasar cümleciklerinin biriyle eşleşmesi gerekir. Fakat cümlecikler arasından bunu sağlayan bir gerçek olmadığı için hedef başarısız olur.
  6. VP bu noktada geriye dönüş işareti koyduğu en son noktaya, yani ikinci alt hedef ve canli(zebra, tirnakli) cümleciğine döner.
  7. Geriye dönüş noktasına geldiğinde, bu noktadan sonra değer almış bütün değişkenler serbest hale gelir. Daha sonra canli(Y, tirnakli) alt hedefine yeni bir çözüm arar.
  8. VP daha önce işaret koyup durduğu satırdan başlamak üzere, geriye kalan cümlecikler arasında tarama yaparak şimdiki alt hedefe uyacak bir çözüm arar. Programımızda alt hedefi doğrulayacak başka bir seçenek bulunmadığından, yapılan çağrı başarısız olur ve VP yeniden bir önceki alt hedefe döner.
  9. Bu kez tur(tirnakli, hayvan) hedefini doğrulamaya çalışır. Çünkü geriye dönüş işareti buraya konulmuştu.
  10. Bütün değişkenler serbest hale getirilir ve yeniden tur(X, hayvan) alt hedefine çözüm arar. Geriye dönüş noktasından sonraki tur(balik, hayvan) cümleciği bu hedefi doğrular ve X=balik değerini alır. VP bu kez geriye dönüş noktasını bu cümleciğin yanına yerleştirir.
  11. VP şimdi kuraldaki ikinci alt hedefi doğrulamak üzere aşağıya doğru hareket eder. Bu tarama yeni bir tarama olduğu için tarama yine cümleciklerin başından, yani canli(Y, tirnakli) cümleciğinden başlar.
  12. canli(alabalik, balik) cümleciği alt hedefi doğrular ve Y=alabalik değerini alır.
  13. Y şimdi ‘alabalik’ değerini aldığı için, yasar(alabalik, suda) alt hedefi çağrılır. Bu da yeni bir çağrı olduğu için program yine baştan başlar.
  14. Cümleciklerde görüldüğü gibi, yasar yüklemleri arasında yasar(alabalik, suda) alt hedefini doğrulayacak bir seçenek yoktur. Bu yüzden çağrı başarısız olur ve bir önceki alt hedefe yeniden dönüş yapılır.
  15. canli(alabalik, balik) geriye dönüş noktasına gidilir.
  16. Bu noktadan sonra değer alın bütün değişkenler yeniden serbest hale geldikten sonra canli(Y, balik) çağrısına cevap aranır.
  17. Bu kez Y=kopekbaligi değeri alt hedefi sağlar.
  18. VP üçüncü alt hedefi yeniden doğrulamaya çalışır. Y ‘kopekbaligi’ değerini aldığı için yasar(kopekbaligi, suda) alt hedefinin doğrulanması gerekir. Bu yeni çağrı doğrulanır, çünkü son cümlecik eşleşmektedir.
  19. Alt hedeflerin doğrulanmasından sonra kuralın baş kısmı da sağlanmış olur. VP, Y değişkeninin aldığı ‘kopekbaligi’ değerini yuzebilir(Ne) kuralındaki Ne değişkenine atar ve böylece Goal bölümündeki write("Bir ",Ne," yüzebilir\n") alt hedefi de çağrılır. Sonuç:
Bir köpekbalığı yüzebilir
Ne=kopekbaligi
1 Solution
4.3. Tarama İşleminin Kontrol Edilmesi

VP’de var olan geriye iz sürme mekanizması bazen gereğinden fazla tarama yapabilir. Bu ise verimi düşürür. Bazen verilen bir problem için sadece bir çözüm bulmak istenebilir. Bazen de, bir çözüm bulunsa bile –varsa- başka alternatif çözümleri de bulmak istenebilir. İşte bu gibi durumlarda geriye dönüş işleminin kontrol edilmesi gerekir.
Geriye İz Sürme işlemini kontrol edebilmek için VP’nin iki özelliğinden faydalanılabilir. Bunlar,: VP’yi geriye iz sürme işlemi yapmaya zorlayan fail yüklemi ve geriye dönüş mekanizmasını engelleyen cut ‘!’ özelliğidir.
4.4. failYükleminin Kullanılması

Alt hedeflerden birinin sağlanamaması durumunda geriye dönüş işlemi yapılır. Bazı durumlarda alternatif çözümleri bulabilmek için bu işlemin yapılması gereklidir. VP’nin fail yüklemi, bir sorgunun başarısız olmasına ve böylece geriye dönüş işleminin yapılmasına imkan tanır.
DOMAINS
isim=symbol
PREDICATES
nondeterm baba(isim, isim)
herkesi_bul
CLAUSES
baba("Ömer ", yavuz).
baba(ahmet, kasim).
Baba(huseyin, veli).
Baba(murat, yusuf).
herkesi_bul:-
baba(X,Y), write(X, Y," Babası\n"),
fail.
herkesi_bul.
GOAL herkesi_bul.
Programdaki dahili hedef doğrulandıktan sonra VP’nin geriye iz sürmesine gerek yoktur. Bundan dolayı baba ilişkisine yapılan ilk çağrı başarılı olur ve sadece bir tek çözüm sağlanmış olur. Fakat yüklem bölümündeki herkesi_bul yüklemi fail özelliğini kullanarak Prologu geriye iz sürme mekanizmasını kullanmaya zorlar ve mümkün olan bütün çözümlerin bulunmasını sağlar. Herkes yükleminin amacı, görüntülenen cevapların daha net olmasıdır.
Herkes yüklemi VP’yi zorlayarak, baba(X,Y) kuralının sağlanması için geriye dönüş işleminin çalıştırılmasını sağlar. Daima olumsuz cevap vereceği için fail kuralının doğrulanması mümkün değildir. Bu yüzden VP daima bir üstteki alt hedefe geriye dönüş yapar. Geriye dönüş olduğunda VP, birden fazla çözüm verebilecek en son hedefe döner. Bu tür bir çağrı belirsiz (non-deterministic) olarak tanımlanır. Belirsiz bir çağrı, belirli olan ve sadece bir tek çözüm sunabilen bir çağrının tam tersidir.
‘write’ yükleminin doğruluğu yeniden sağlanamaz, çünkü yeni çözümler sunmaz. Haliyle VP kuraldaki ilk alt hedefe geriye dönüş yapar.
‘fail’ yüklemini takiben başka alt hedeflerin yazılması hiçbir işe yaramaz. Çünkü ‘fail’ yükleminin kendisi daima başarısız olacağından, ‘fail’ yüklemini takip eden bir alt hedefin sorgulaması mümkün değildir.
4.5. Geriye İz Sürmeyi Engelleme

VP’de ünlem işareti ile gösterilen (!) cut yükleminden itibaren geriye dönüş mümkün değildir. Cut yüklemi, bir kuralın içinde herhangi bir alt hedefmiş gibi yazılır. Program çalışırken cut alt hedefi daima doğrulanır ve işlem bir alt hedefe geçer. Bu hedeften önceki alt hedeflere ve cut komutunu içeren alt hedefin kendisine geriye dönüş artık mümkün değildir.
Cut komutu iki amaç için kullanılır:
  1. Alternatif çözümün mümkün olmadığına önceden karar verilirse, vakit ve bellek kaybını önlemek için bu komut kullanılabilir. Böylece program daha hızlı çalışır. Buna ‘green cut (Olumlu Cut)’ denir.
  2. Programın kendi mantığı cut yüklemini gerektiriyorsa, alternatif alt hedeflerin incelenmesini önlemek için de cut kullanılır. Buna ise ‘red cut (Olumsuz Işık)’ adı verilmektedir.
4.5.1. Cut Komutunun Kullanımı

Bu bölümde cut komutunun kullanımı ile ilgili örnekler üzerinde çalışalım. r1, r2, r3 kuralları r yüklemini, a, b, c ise alt hedefleri gösterir.
Bir kural içindeki bir alt hedefe geri dönüşü engellemek için
R1:- a, b, !, c. yazılabilir.
Yukarıdaki kuralın anlamı şudur: Kural içerisindeki a ve b alt hedeflerini doğrulayan bir çözüm bulunduğunda programı durdur. Bu yüzden cut komutunu geçip c alt hedefine geçmek mümkün değildir. Dolayısıyla a ve b için alternatif çözümler mümkün olsa da, sadece bulunan ilk çözümle yetinilir. Cut komutu r1 yüklemini tanımlayan başka bir cümlecik içine gitmeyi de engeller.
Örnek
PREDICATES
araba_satin_al(symbol,symbol)
nondeterm araba(symbol,symbol,integer)
renkler(symbol,symbol)
CLAUSES
araba_satin_al(Model,Renk):-
araba(Model,Renk,Fiyat),
renkler(Renk,cazip),!,
Fiyat > 20000.
araba(murat,yesil,25000).
araba(mersedes,siyah,24000).
araba(bmw,kirmizi,28000).
araba(renault,kirmizi,24000).
araba(toyota, sari, 30000).
renkler(kirmizi,cazip).
renkler(siyah,orta).
renkler(yesil,berbat).
renkler(sari, cazip).
GOAL araba_satin_al(bmw, Hangi_renk).
Bu örneğin verilmesinin amacı, rengi cazip, fiyatı da uygun olan bir BMW almaktır. Veri tabanında BMW için zaten bir satır vardır. Prolog’un yapması gereken tek şey, fiyatının verilen şarta uyup uymadığını kontrol etmektir. Goal içerisindeki ! komutu, BMW için fiyat uygun değilse, başka bir araba aranmasını engeller. Programı çalıştırıldığında
Hangi_renk=kirmizi
1 Solution
yanıtı alınır.
4.5.2. Geriye İz Sürmeyi Engelleme

Cut komutu, bir yüklem için doğru olan bir cümlenin seçildiğini belirtmek için de kullanılabilir.
r(1):-!, a, b, c
r(1):-!, d
r(1):-!, c
r(_):- write (“Cümlelerin tamamı buraya yazılır”).
Cut komutu r yüklemini deterministic (belirli) yapar. Dolayısıyla r yüklemi bir tamsayı argümanı ile çağrılır. Yapılan çağrının r(1) olduğunu kabul edelim. Prolog yapılan çağrıya uygun bir eşleşme ararken, r’yi tanımlayan bir cümlecik bulur. Birden fazla çözüm mümkün olduğundan, Prolog ilk cümleciğe geri dönüş noktası işareti koyarak aşağıda doğru işleme devam eder ve geri kalan satırlara geçer. Olacak ilk şey, cut komutu geçmektir. Böyle yapmak artık başka bir r cümleciğine geri dönüşü ortadan kaldırır ve geri dönüş noktası ortadan kalktığı için, programın çalışma hızı oldukça artar.
 

arago_W&B

Üye
1 Mar 2008
139
3
Bu tür yapının diğer dillerde yazılan ‘Case’ yapılarına benzediği görülür. Deneme şartı, kuralın baş tarafında yazılır. Yukarıdaki satırları daha anlaşılır yapmak için şöyle yazalım:
r(x):- X=1, !, a, b, c.
r(x):- X=2, !, d.
r(x):- X=3, !,c.
r(_):-write (“Cümlelerin tamamı buraya yazılır”).
Örnek:
PREDICATES
arkadas(symbol,symbol)
kiz(symbol)
sever(symbol,symbol)
CLAUSES
arkadas(ahmet,fatma):- kiz(fatma), sever(ahmet,fatma),!.
arkadas(ahmet,mehmet):- sever(mehmet,futbol),!.
arkadas(ahmet,esra):- kiz(esra).
kiz(tuba).
kiz(fatma).
kiz(esra).
sever(mehmet,futbol).
sever(ahmet,esra).
GOAL arkadas(ahmet,Kimin_Arkadasi).
Program akışı içerisinde Cut komutu kullanılmazsa, yukarıdaki örnekten iki ayrı sonuç elde edilir. Yani Ahmet hem Mehmet’in hem de Esra’nın arkadaşıdır. Fakat arkadas iliskisini tanımlayan ilk cümledeki Cut komutu, bu cümlenin doğrulanıp Ahmet’in bir arkadaşının bulunması durumunda, artık ikinci bir arkadaş bulmanın gereksiz olduğunu vurgular. Bu yüzden yukarıdaki Goal için sadece Mehmet’in Ahmet’in arkadaşı olduğu cevabı görüntülenir.
4.6. Determinism ve Cut

Yukarıdaki örnekte ‘arkadas’ yüklemi Cut kullanılmadan tanımlanmış olsaydı, non-deterministic, yani geriye iz sürme işlemiyle birden fazla çözüm üretmesi mümkün bir yüklem olacaktı. Programların ihtiyaç duyacakları bellek miktarı artacağından, özellikle non-deterministic yüklemler ile çalışılırken dikkatli olmak gerekir. VIP non-deterministic yüklemleri dahili olarak kontrol etmekle beraber, güvenli bir program yazmak için check_determ derleyici direktifini kullanmak faydalıdır. Eğer check_determ programın hemen ilk satırına yerleştirilirse, programın çalıştırılması esnasında non-deterministic yüklemlere gelindiğinde bir uyarı mesajı görüntülenir. Böylece non-deterministic olan bir yüklemin gövde kısmında (body) uygun bir Cut komutu kullanarak yüklemi deterministic hale getirebiliriz.
4.7. Not Yüklemi

Genel Not Ortalaması 3.5 olan ve beklemeli olmayan Şeref Öğrencisini bulman program:
DOMAINS
isim= symbol
gno= real
PREDICATES
nondeterm seref_ogrencisi(isim)
nondeterm ogrenci(isim, gno)
beklemeli(isim)
CLAUSES
seref_ogrencisi(Isim):-ogrenci(Isim,Gno),Gno>=3.5, not(beklemeli(Isim)).
ogrenci ("Kasım Yenigün", 3.5).
ogrenci("Ferit DAĞDEVİREN", 2.8).
ogrenci("Orhan AYDIN", 3.8).
beklemeli("Kasım Yenigün").
beklemeli("Ferit DAĞDEVİREN").
GOAL seref_ogrencisi(Seref_Ogrencisinin_Adi_Soyadi).
Not komutunu kullanırken dikkat edilmesi gereken tek bir kural vardır: Not komutu, sadece alt hedefin doğruluğunun ispatlanamaması durumunda işlem görür. Serbest değişkenli bir alt hedef Not içerisinden çağrıldığı zaman, Prolog, Free variables not allowed in ‘not’ or ‘retractall’ (Not veya retractall içerisinde serbest değişkenler kullanılamaz) hata mesajını verecektir. Prolog’un bir alt hedefteki serbest değişkenlere değer ataması için, bu alt hedefin başka cümlecikle eşleşmesi ve alt hedefin doğrulanması gerekir. Not içeren bir alt hedefteki bağımsız değişkenleri kullanmanın en doğru yolu anonim değişkenler (_) kullanmaktır.
Aşağıda bu konu ile ilgili yanlış ve doğru örnekler verilmiştir:
sever(ahmet, Herhangi_Biri):- /* ‘Herhangi_Biri çıktı argümanıdır’*/
sever(esra, Herhangi_Biri),
not(nefret_eder(ahmet, Herhangi_Biri).
Burada Herhangi_Biri, nefret_eder(ahmet, Herhangi_biri) alt hedefinin doğru olmadığı ispatlanmadan önce Herhangi_biri argümanı sever(esra, Herhangi_biri) alt hedefindeki Herhangi_biri argümanına atanmış olur. Dolayısıyla yukarıdaki kod tam olarak arzu edildiği gibi çalışır. Yukarıdaki kısa program
sever(ahmet, Herhangi_biri):- /* ‘Doğru çalışmaz’*/
not(nefret_eder(ahmet, Herhangi_biri),
sever(esra, Herhangi_biri).
şeklinde yazılacak olursa, ilk önce Not ile başlayan cümlecik çağrılmış olur. Not cümleciği içinde serbest değişken tanımlamak mümkün olmadığı için, Prolog hata mesajı vermiş olur. Çünkü not(nefret_eder(ahmet, Herhangi_Biri) cümleciğindeki Herhangi_biri argümanı serbest değişkendir ve hiçbir değeri yoktur. Programdaki Herhangi_biri yerine anonim değişken olan (_) kullanılsa bile, Prolog yine yanlış bir sonuç verecektir.
sever(ahmet, Herhangi_biri):- /*Doğru çalışmaz*/
not(nefret_eder(ahmet, _),
sever(esra, Herhangi_biri).
Çünkü yukarıdaki cümlelerden anlaşılan şudur: Eğer Ahmet’in nefret ettiği bir şey bilinmiyorsa ve eğer esra Herhangi_biri’ni seviyorsa, Ahmet Herhangi_biri’ni sever. Anlatılmak istenen şey ise şudur: Esra’nın sevdiği ve Ahmet’in de nefret etmediği Herhangi_biri varsa, Ahmet bu Herhangi_biri’ni sever.
Not yüklemini kullanırken çok dikkatli olmak gerekir. Yanlış kullanım, ya hata mesajı alınmasına ya da program içerisinde mantıksız bir yapıya neden olacaktır.
Örnek:
PREDICATES
Nondeterm alisveristen_hoslanir(symbol)
Nondeterm kredi_kartina_sahip(symbol, symbol)
kredisi_bitmis(symbol, symbol)
CLAUSES
alisveristen_hoslanir(Kim):-
kredi_kartina_sahip(Kim,Kredi_karti),not(kredisi_bitmis(Kim,Kredi_karti)),
write(Kim, Kredi_karti, "ile alışveriş yapabilir\n").
kredi_kartina_sahip(yavuz, visa).
kredi_kartina_sahip(yavuz, diners).
kredi_kartina_sahip(ahmet, shell).
kredi_kartina_sahip(mehmet, masterkart).
kredi_kartina_sahip(asaf_bey, akbank).
kredisi_bitmis (yavuz, diners).
kredisi_bitmis (asaf_bey, masterkart).
kredisi_bitmis (yavuz, visa).
GOAL alisveristen_hoslanir(Kim).


Örnek:
DOMAINS
isim,cinsiyet,meslek,cisim,yardimci,madde = symbol
yas=integer
PREDICATES
nondeterm sahis(isim, yas, cinsiyet, meslek)
nondeterm iliskili(isim, isim)
ile_oldurdu(isim, cisim)
oldurdu(isim)
nondeterm katil(isim)
sebep(yardimci)
uzerinde_leke_var(isim, madde)
sahip(isim, cisim)
nondeterm birbirine_benzer(cisim, cisim)
nondeterm sahip_oldugu_cisim(isim, cisim)
nondeterm supheli(isim)
/* * * Katil hakkındaki gerçekler * * */
CLAUSES
sahis(huseyin,55,m,arastirma_gorevlisi).
sahis(yavuz,25,m,futbolcu).
sahis(yavuz,25,m,kasap).
sahis(ahmet,25,m,yankesici).
iliskili(fatma,ahmet).
iliskili(fatma,huseyin).
iliskili(deniz,ahmet).
ile_oldurdu(deniz,sopa).
oldurdu(deniz).
sebep(para).
sebep(kiskanclik).
sebep(durustluk).
uzerinde_leke_var(huseyin, kan).
uzerinde_leke_var(deniz, kan).
uzerinde_leke_var(yavuz, camur).
uzerinde_leke_var(ahmet, cikolata).
uzerinde_leke_var(fatma,cikolata).
sahip(huseyin,tahta_bacak).
sahip(ahmet,tabanca).
/* Temel Bilgiler */
birbirine_benzer(tahta_bacak, sopa).
birbirine_benzer(demir, sopa).
birbirine_benzer(makas, bicak).
birbirine_benzer(futbol_sopasi, sopa).
sahip_oldugu_cisim(X,futbol_sopasi):-sahis(X,_,_,futbolcu).
sahip_oldugu_cisim(X,makas):-sahis(X,_,_,kuafor).
sahip_oldugu_cisim(X,Cisim):-sahip(X,Cisim).
/* Susan'ın oldürüldüğü silaha sahip herkesi şüpheli kabul edilsin */
supheli(X):-
ile_oldurdu(deniz,Silah) ,
birbirine_benzer(Cisim,Silah) ,
sahip_oldugu_cisim(X,Cisim).
/* Susan ile ilişkisi olan insanlar da şüpheliler listesine girmeli */
supheli(X):-
sebep(kiskanclik),
sahis(X,_,m,_),
iliskili(deniz,X).
/* Susan'ın, ilişkilerinden haberdar olduğu bayanlar da şüpheli listemizde olmalı */
supheli(X):-
sebep(kiskanclik),
sahis(X,_,f,_),
iliskili(X,Erkek),
iliskili(deniz,Erkek).
/* Şüpheli, para için katil olan bir yankesici olabilir */
supheli(X):-
sebep(para),
sahis(X,_,_,yankesici).
katil(Katil):-
sahis(Katil,_,_,_),
oldurdu(Olduruldu),
Olduruldu <> Katil, /* It is not a suicide */
supheli(Katil),
uzerinde_leke_var(Katil,Devam),
uzerinde_leke_var(Olduruldu,Devam).
GOAL
katil(Katil_Kim).
4.8. Prosedürel Açıdan Prolog

Prolog tanımsal yapıya sahip bir dildir. Program hazırlarken problem olgular(önceden bilinen gerçekler) ve kurallarla tanımlanır. Bunu takiben bilgisayardan çözüm bulması beklenir. Pascal, BASIC ve C gibi diller ise tamamen prosedürlere dayanırlar. Bilgisayarın belli bir probleme çözüm bulabilmesi için, programcının, yapılması gereken işlemleri alt programlar ve fonksiyonlar halinde adım adım tanımlaması gerekir.
 

arago_W&B

Üye
1 Mar 2008
139
3
4.8.1. Kurallar ve Olguların Prosedürlere Benzerliği

Prolog’daki bir kuralı diğer dillerdeki bir procedure olarak görmek mümkündür. Örneğin
sever(ahmet, Birsey):- sever(gul, Birsey).
şeklindeki bir kural ‘Ahmet’in bir şeyi sevdiğini ispatlamak için, Gül’ün de aynı şeyi sevdiğini ispat et’ anlamına gelir. Aynı şekilde
sever(Orhan, Baklava).
şeklindeki Prolog kuralı “Orhan’ın baklava sevdiğini ispat etmek için dur” anlamındaki bir procedure olarak düşünmek mümkündür. Burada sever(Kim, Ne) şeklinde bir sorgu gelirse, Kim ve Ne serbest değişkenleri sırasıyla Orhan ve Baklava değerlerini alırlar.
Case ifadesi, boolean testleri ve goto komutu diğer dillerde mevcut olan procedure örnekleridir. Benzer işlemleri, kuralları kullanarak yapabiliriz.
4.8.2. Bir Kuralın Case ifadesi Gibi Kullanılması

Prolog’daki Kural ile diğer dillerdeki Procedure arasındaki büyük farklardan biri, Prolog’un aynı procedure için birden fazla alternatif tanımlama imkanı vermesidir.
Pascal’daki CASE ifadesi kullanıyormuş gibi, her argüman değeri için farklı bir tanım yazarak çoklu tanım kullanabilirsiniz. Prolog kuralları peşpeşe kullanarak eşleşenleri bulur ve kuralın tanımladığı işlemi yapar.
Örnek:
PREDICATES
nondeterm basilan_tus(integer)
CLAUSES
basilan_tus(1):-
nl,
write("1 Tuşuna Bastınız."), nl.
basilan_tus(2):-
nl,
write("2 Tuşuna Bastınız."), nl.
basilan_tus(3):-
nl,
write("3 Tuşuna Bastınız."), nl.
basilan_tus(N):-
nl,
N<>1, N<>2, N<>3, write("Hangi Tuşa Bastığınızı Bilmiyorum"), nl.
GOAL write("1-3 arasında bir sayı yazınız: "), readint(Sayi), basilan_tus(Sayi).
Örnekte, 1, 2 veya 3 haricindeki rakamlar girildiğinde eşleşme olamaz ve çözüm bulunmaz.
4.8.3. Bir Kural İçinde Test Yapmak

Yukarıdaki örnekte geçen basilan_tus(N) cümleciğinde; verilecek herhangi bir değere otomatik olarak N’e atanacaktır. Burada verilen sayının sadece 1-3 aralığı dışında olması durumunda ‘Hangi Tuşa Bastığınızı Bilmiyorum’ mesajının görüntülenmesi gerekir. Bu N<>1, N<>2, N<>3 alt hedefleri ile gerçekleştirilmektedir. Prolog ilk önce yazılan değerin 1-3 arasında olup olmadığını doğrulamaya çalışır. Doğru olmadığını görünce geriye dönüş işlemi yapmaya çalışır. Fakat başka alternatif olmadığı için bu cümlenin geriye kalan kısmına geçiş yapamaz.
Basilan_tus ilişkisi atanacak olan seçeneklere dayanır. Eğer basilan_tus ilişkisi argümanı serbest olan bir değişken ile çağılırsa, GOAL bu cümlelerin hepsiyle eşleşir ve ilk üç kural alternatif çözümler olarak sunulur. Son cümle ise hataya neden olur. Çünkü bağımsız bir değişkeni bir sayı ile eşleştirmek mümkün değildir.
4.8.4. Cut Komutunun Goto Gibi Kullanılması

Yukarıdaki örnek vakit kaybına neden olur. Çünkü doğrulanan bir kural bulunsa bile, Prolog’un son kuralı da test edip başka alternatif araması gerekir. Prolog’a alternatif aramaktan vazgeçmesini söylemek için Cut komutu kullanılabilir. Bunun sonucu, bize zaman ve bellek tasarrufu sağlanır.
Yukarıdaki program, şimdi de Cut komutu ile yazılsın.
PREDICATES
nondeterm basilan_tus(integer)
CLAUSES
basilan_tus(1):- !,
nl,
write("1 Tuşuna Bastınız."), nl.
basilan_tus(2):- !,
nl,
write("2 Tuşuna Bastınız."), nl.
basilan_tus(3):- !,
nl,
write("3 Tuşuna Bastınız."), nl.
basilan_tus(_):- !, write("Hangi Tuşa Bastığınızı Bilmiyorum"), nl.
GOAL write("1-3 arasında bir sayı yazınız: "), readint(Sayi), basilan_tus(Sayi).
Cut komutunun işleme girebilmesi için Prolog’un içinde Cut bulunan bir kurala gitmesi ve Cut komutunun bulunduğu noktaya kadar gelmiş olması gerekir.
Cut komutu basilan_tus(X):- X>3, !, write(“Yazdığınız rakam çok yüksek”) gibi testlerden önce gelebilir. X>3 alt hedefi doğrulandığı anda Cut komutu önemli hale gelir. Burada kuralların sırası oldukça önemlidir. 13. örnekte kurallar; arzu edilen sıraya göre yazılabilir. Çünkü onlardan sadece biri girilen bir sayı ile eşleşir. Fakat Cut kullanılan yukarıdaki örnekte, bilgisayarın write("Hangi Tuşa Bastığınızı Bilmiyorum") kuralına diğer üç kuralı denemeden önce kesinlikle geçmediğinden emin olmak gerekir. Çünkü buradaki Cut komutları red_cut, yani olumsuz cut, görevi görürler ve programın mantığını değiştirirler.
Eğer yukarıdaki programda X<>1, X<>2 ve X<>3 şeklindeki karşılaştırma anahtarlarını tutup her cümleye sadece bir Cut komutu yerleştirilirse, buradaki Cut komutları Green Cut olarak görev yaparlar. Cut, diğer programlama dillerinde tıpkı GOTO komutu gibi görev görür. Cut komutunun kullanımı faydalıdır, fakat içinde Cut kullanılan programları anlamak bazen zor olabilir.
4.9. Hesaplanmış Değerleri Görüntüleme

Program akışında, ilk başta herhangi bir değeri olmayan argümanlar, daha sonra belirli değerle alırlar. Örneğin
sever(orhan, gulsah).
şeklindeki bir olgu
sever(orhan, Kim)
şeklindeki bir hedef cümlesindeki Kim argümanına ‘Gulsah’ değerini atamış olur. Yani
GOAL sever(orhan, Kim) hedef cümlesindeki Kim argümanı ilk önce serbest olmasına rağmen, sever(orhan, gulsah) olgusunu çağırdığı anda olgudaki Gulsah değeri Kim argümanına atanır ve Kim argümanı sınırlı hale gelir.
Örnek:
PREDICATES
nondeterm ekrana_yaz(integer, symbol)
CLAUSES
ekrana_yaz(0, sifir).
ekrana_yaz(Sayi, negatif):- Sayi<0.
ekrana_yaz(Sayi, pozitif):- Sayi>0.
GOAL ekrana_yaz(14, Sayinin_isareti).
‘ekrana_yaz’ ilişkisinin ilk argümanı daima sabit bir sayı ve bağlı bir değişken olmak zorundadır. İkinci argüman ise sınırlı veya sınırsız bir değişken olabilir. İlk değişkene bağlı olarak sıfır, negatif veya pozitif bir sayı olabilir.
Yukarıdaki GOAL cümleciğinin bulacağı cevap elbette yes olacaktır. Çünkü 14 sıfırdan büyük bir sayıdır ve pozitiftir. Burada sadece 3. cümlecik doğrudur.
GOAL ekrana_yaz(14, negatif).
Hedef cümlesiyle aynı prosedür takip edilir ve no cevabı alınır. Prolog’un sonuç alması incelenirse,
  • İlk önce ilk cümlecik incelenir. Belirle ilişkisindeki argümanlar, yani 14 ve negatif değerleri, 0 ve sifir değerleriyle eşleşmezler.
  • İkinci cümleciğe sıra geldiğinde, Sayi 14’e eşitlenir fakat sayi<0 testi doğrulanamaz.
  • Üçüncü argümana gelindiğinde bu kez ikinci argümanlar eşleşmez, yani pozitif kelimesi negatif ile eşleşemez.
Anlamlı bir cevap almak için örneğin GOAL belirle(14, Sayinin_Isareti) kullanılırsa,
Sayinin_Isareti=pozitif
1 Solution
cevabı alınır.
Yukarıdaki örneğin çalışması esnasında, işlemler aşağıdaki sıra ile yapılacaktır.
ekrana_yaz(14, Sayinin_Isareti) hedef cümlesi, ilk cümleciğin ekrana_yaz(0, sifir) kısmıyla eşleşmez. Bu yüzden ilk cümlecik kullanılamaz.
  1. ekrana_yaz(14, Sayinin_Isareti) hedef cümlesi ikinci cümleciğin baş kısmıyla eşleşir ve Sayi=14, Sayinin_Isareti=negatif olur. Fakat hemen sonraki Sayi<0 yanlış olduğundan Prolog bu cümlecikten geriye döner ve Sayi=14 değeri iptal edilir.
  2. ekrana_yaz(14, Sayinin_Isareti) hedef cümlesi üçüncü cümleciğin baş kısmıyla eşleşir ve Sayi=14, Sayinin_Isareti=pozitif olur. Sayi>0 eşitliği de sağlandığı için Prolog artık geriye iz sürme işlemini yapmaz ve sonucu görüntüler.
 

arago_W&B

Üye
1 Mar 2008
139
3
5. BASİT VE BİLEŞİK NESNELER

Şimdiye kadar Prolog’da kullanılan veri nesnelerinden number, symbol, string gibi birkaç tip incelenmiştir. Bu bölümde basit ve bileşik veri türlerinin tamamı incelenecektir. Standart tip olarak tanımlanabilen veriler, bazı bileşik veri yapılarını içermezler. Bu yüzden farklı veri yapılarına göz atarak, bunların domains ve predicates bölümlerinde nasıl tanımlanabileceği göreceğiz.
5.1. Basit veri nesneleri

Basit bir veri nesnesi, bir değişken veya bir sabitten oluşabilir. Sabit, constants bölümünde tanımlanan veri tipi değil; char, integer, symbol, string gibi değişmeyen bir nesnedir.
5.1.1 Veri Nesneleri Olan Değişkenler

VIP değişkenleri A-Z arasındaki büyük bir harf veya (_) ile başlamalıdır. (Değişken isimlerinde ç, İ, ö, ğ, ş vs. gibi Türkçe karakterler kesinlikle kullanılamaz) Yalnız başına kullanılan (_) değişkeninin anonim değişken olduğunu ve herhangi bir değerle eşleşebileceği bilinmektedir. Prolog’daki değişkenler global değil, lokaldir. Yani iki ayrı cümlecikte aynı isimle -örneğin X- gösterilen bir değişken farklıdır. Eşleşme sırasında birbiriyle eşleşebilir, fakat temelde birbiri üzerinde hiçbir etkisi yoktur.
5.1.2. Veri Nesneleri Olan Sabitler

Sabitler karakter, sayı veya atom biçiminde olabilirler.
5.1.3. Karakterler

Karakterler char kelimesi ile gösterilir ve 0-9, A-Z ve a-z, ASCII 127 karakter tablosundaki değerleri alabilirler. Fakat ASCII 32 (boşluk) ve daha küçük karakterler kontrol amacıyla kullanılırlar.
Tek karakterlik bir sabit şöyle yazılır:
‘a’ ‘3’ ‘*’ ‘[FONT=Symbol, serif][/FONT]’ ‘W’ ‘A’ ‘\\’=\ ‘\’’=’ ‘\225’=[FONT=Symbol, serif][/FONT] (ASCII 225)
Bunların dışında başka fonksiyonları olan karakterler de vardır.
‘\n’ Yeni satıra geçiş komutu
‘\r’ Satır sonu
‘\t’ Yatay sekme (tab)
5.1.4. Sayılar

Sayılar tamsayı ve reel olabilirler. Reel sayılar 10-308-10+308arasında değişirler.
Örnek:
Tamsayılar Reel Sayılar
10 3.
-77 34.96
32034 -32769
-10 4*10+27
5.1.5. Atomlar

Bir atom symbol veya string olabilir. İkisi arasındaki fark genelde Prolog’un çalıştırıldığı sisteme bağlıdır.
Prolog string ve symbol tipleri arasında otomatik dönüştürme yapabilir. Dolayısıyla symbol ve string tipindeki değişkenler birbirinin yerine kullanılabilirler. Fakat programcılıkta yaygın olan adet, çitf tırnak (“) içine alınması gereken sabitleri string, çitf tırnak gerektirmeyen sabitleri de symbol olarak kabul etmektir.
Symbol: küçük harfle başlayan ve sadece harf, rakam ve _ karakterlerini içerir.
String: Çift tırnak içine alınabilen ve string sonunu belirleyen 0 (Sıfır) hariç, herhangi bir karakteri içerebilir.
Symbol String
Yemek “Yavuz AYDIN”
Ahmetin_babasi “ 12. Cadde”
A “a”
PdcProlog “Visual Prolog Development Center”
5.2. Bileşik Veri Nesneleri ve Fonksiyon Operatörleri

Bileşik veri nesneleri, birden fazla parçadan oluşan verileri tek bir parçaymış gibi kullanma imkanı tanır. Mesela 16 Mayıs 1998 tarihi gün, ay ve yıl olarak 3 parçadan oluşan bir bilgiyi temsil eder. Bu tür bir bilgiyi tek bir parçaymış gibi kullanmaya imkan tanıyan sabitler vardır.
Örnek:
Domains

Islem_tarihi= date(string, unsigned, unsigned)
şeklindeki bir tanımdan sonra D=date(“Mayıs”, 16, 1998) şeklinde yazılabilir. Burada D bir olgu değil, symbol veya sayı gibi kullanılabilecek bir veridir. Bu tür ifadeler genelde bir fonksiyon operatörü ve takip eden 3 argüman ile başlar. Operatörler herhangi bir hesaplama yapamazlar. Sadece bir tür bileşik veri nesnelerini tanımlar ve argümanların tek veriymiş gibi tutulmasına imkan tanır.
Bileşik veri nesnelerinin argümanları da bileşik olabilir. Örneğin
Dogum_Gunu​
Kisi date​
“Ahmet”“SAGMEN” “Mart” 15 1976​
şeklinde gösterilen bir tarihi Prolog’da
dogum_tarihi(kisi(“Ahmet”,“SAGMEN”),date(“Mart”,15,1976)) şeklinde yazılabilir.
Bu örnekte dogum_tarihi bileşik nesnesinin iki bölümü vardır: kisi(“Ahmet”, “SAGMEN”) ve date(“Mart”, 15, 1976). Buradaki operatörler kisi ve date’dir.
5.3. Bileşik Nesnelerin Eşleştirilmesi

Bileşik bir nesne basit bir değişken veya kendisine uyan diğer bir bileşik nesne ile eşleşebilir. Örneğin date(“Nisan”, 18, 1983) şeklindeki bir clause tarih clause’una tam olarak eşleşir. Aynı şekilde date(“Nisan”, 18, 1983) date(Ay, Gun, Yil) cümleciğinde Ay=Nisan, Gun=18, Yil=1983 değerlerine atanır.
5.4. Bileşik Nesneleri Eşleştirmek İçin ‘=’ Sembolünün Kullanılması

VIP iki durumda eşleştirme işlemi yapar. İlki bir Goal veya çağrı fonksiyonunun bir cümleciğin baş kısmıyla eşleşmesi durumunda meydana gelir. İkincisi ise ‘=’ işaretinin argümanlar arasında kullanılması durumunda meydana gelir.
Prolog, eşitliğin her iki tarafındaki aynı işaretli nesneleri eşleştirmek için gerekli bağlantıları yapar. Aşağıdaki örnekte, soy isimleri aynı olan iki kişiyi bulup her ikisinin adreslerini eşitleyelim.
DOMAINS
sahis=sahis(isim, adres)
isim=isim(adi, soyadi)
adres=adres(cadde, sehir, ulke)
cadde=cadde(cadde_no, cadde_ismi)
sehir, ulke, cadde_ismi=string
adi, soyadi= string
cadde_no= integer
GOAL
P1 = sahis(isim(orhan, aydin), adres(cadde(5, "1. Cadde"), "Elazig", "Turkiye")),
P1= sahis(isim(_, aydin), Adres),
P2= sahis(isim(oktay, aydin), Adres),
write("Birinci Sahis =", P1), nl,
write("İkinci Sahis =", P2), nl.
5.5. Birden Fazla Nesneyi Tek Nesne Olarak Kullanmak

Prolog’da yazılmış programlarda bileşik nesneleri tek bir nesne gibi kullanmak kolaydır. Bu da programcılığı oldukça kolaylaştırır. Örneğin
sahiptir(fatih, kitap(“Visual Prolog İle Programlama”, “Prof.Dr. Asaf VAROL”)).
cümlesi ‘Fatihin Prof.Dr. Asaf Varol tarafından yazılan Visual Prolog ile Programlama adlı bir kitabı var’ anlamındadır. Benzer şekilde;
sahip(fatma, sevgili(can)).
cümlesi “Fatma’nın, ismi Can olan bir sevgilisi var” anlamına gelir. kitap(“Visual Prolog İle Programlama”, “Prof.Dr. Asaf VAROL”) ve sevgili(can) cümlelerdeki bileşik nesnelerdir.
Bileşik nesne kullanmanın önemli bir avantajı, birden fazla argümandan oluşan cümleleri sadece bir argüman olarak kullanabilmektir.
Örnek:
Basit bir telefon rehberi veritabanı programı
PREDICATES
Adres_listesi(symbol, symbol, symbol, symbol, integer, integer) /*(adi, soyadi, telefonu, ay, gun, yil)*/
clauses
adres_listesi(davut, yildirim, 3128456, ocak,6, 1978).
adres_listesi(maksut, hazneci, 3154878, nisan,14, 1969).
adres_listesi’ndeki 5 argümanı
sahis(Adi, Soyadi), dogum_tarihi(Ay,Gun,Yil).
şeklinde yazmak mümkündür. Yeni şekliyle program şöyle yazılabilir:
Domains
Adi= sahis(symbol, symbol) /* (Adi, Soyadı)*/
Dogum_tarihi= d_tarihi(symbol, integer, integer) /*(Ay, Gün, Yıl)*/
Telefon_no= symbol /* Telefon no*/
Predicates
adres_listesi(adi, telefon_no, d_tarihi)
clauses
adres_listesi(sahis(davut, yildirim), 3128456, d_tarihi(ocak,6, 1978)).
adres_listesi(sahis(maksut, hazneci), 3154878, d_tarihi(nisan,14, 1969)).
Şimdi yukarıdaki küçük programa birkaç kural daha ilave edip, doğum tarihleri bugünün tarihi ile uyuşanları bulmaya çalışalım. Programda standart yüklem olan date kullanılarak bugünün tarihi bilgisayardan alınacaktır.
DOMAINS
adi = sahis(symbol,symbol) /* (Adı, Soyadı) */
dogum_gunu = d_gunu(symbol,integer,integer) /* (Ay, Gun, Yıl) */
tel_no = symbol /* Telefon Numarası */
PREDICATES
nondeterm tel_listesi(adi,symbol,dogum_gunu)
d_gunu_ayini_bul
ay_donustur(symbol,integer)
d_gunu_ayini_kontrol_et(integer,dogum_gunu)
sahsi_yaz(adi)
CLAUSES
d_gunu_ayini_bul:-
write("====Bu ay doğanların listesi ======="),nl,
write(" Adı\t\t Soyadı\n"),
write("=============================="),nl,
date(_, Bu_ay, _), /* Tarihi bilgisayardan oku */
tel_listesi(Sahis, _, Date),
d_gunu_ayini_kontrol_et(Bu_ay, Date),
sahsi_yaz(Sahis),
fail.
d_gunu_ayini_bul:-
write("\n\n Devam etmek için herhangi bir tuşa basın "),nl,
readchar(_).
sahsi_yaz(sahis(Adi,Soyadi)):-
write(" ",Adi,"\t\t ",Soyadi),nl.
d_gunu_ayini_kontrol_et(Yeni_ay,d_gunu(Ay,_,_)):-
ay_donustur(Ay,Ay1),
Yeni_ay = Ay1.
tel_listesi(sahis(paki, turgut), "267 78 41", d_gunu(ocak, 3, 1965)).
tel_listesi(sahis(arif, gurel), "338 41 23", d_gunu(subat, 5, 1972)).
tel_listesi(sahis(mehmet_can, hallac), "512 56 53", d_gunu(mart, 3, 1965)).
tel_listesi(sahis(cuma, cetiner), "267 22 23", d_gunu(nisan, 29, 1963)).
tel_listesi(sahis(omer, akgobek), "355 12 12", d_gunu(mayis, 12, 1971)).
tel_listesi(sahis(fatih, dilekoglu), "438 63 42", d_gunu(haziran, 17, 1970)).
tel_listesi(sahis(levent, aksun), "567 84 63", d_gunu(haziran, 20, 1972)).
tel_listesi(sahis(cengiz, gok), "255 56 53", d_gunu(temmuz, 16, 1973)).
tel_listesi(sahis(kasim, yenigun), "132 22 23", d_gunu(agustos, 10, 1968)).
tel_listesi(sahis(husamettin, bulut), "412 48 34", d_gunu(eylul, 25, 1967)).
tel_listesi(sahis(arif, demir), "315 24 21", d_gunu(ekim, 20, 1992)).
tel_listesi(sahis(sezen, demir), "233 13 12", d_gunu(kasim, 9, 1980)).
tel_listesi(sahis(nebahat, arslan), "337 22 23", d_gunu(kasim, 15, 1987)).
tel_listesi(sahis(leyla, aydin), "145 41 50", d_gunu(aralik, 24, 1940)).
ay_donustur(ocak, 1).
ay_donustur(subat, 2).
ay_donustur(mart, 3).
ay_donustur(nisan, 4).
ay_donustur(mayis, 5).
ay_donustur(haziran, 6).
ay_donustur(temmuz, 7).
ay_donustur(agustos, 8).
ay_donustur(eylul, 9).
ay_donustur(ekim, 10).
ay_donustur(kasim, 11).
ay_donustur(aralik, 12).
GOAL d_gunu_ayini_bul.
Yukarıdaki program kodu incelendiğinde, bileşik nesnelerin neden faydalı olduğu açıkça görülür. Dogum_tarihi_ayi yüklemi, en yoğun kullanılan cümle durumdadır.
  1. Program ilk önce sonuçları bir pencerede görüntüler.
  2. Sonra sonuçların yorumlanacağı bir başlık kısmı görüntülenir.
  3. Daha sonra hazır fonksiyonlardan biri olan date kullanılarak bilgisayarın saatinden bugünkü tarih okunur ve ay belirlenir.
  4. Bundan sonra yapılması gereken tek şey, satırlar halinde sıralanan veritabanından isim, telefon no, doğum tarihi okutmaktır. Burada doğum tarihi sistemden okunan ay ile karşılaştırılıp aynı olanlar bulunur. adres_listesi(Sahis,_, Date) çağrısı adı ve soyadını Sahis değişkenine atar ve sahis operatörü Sahis’a atanmış olur. Date değişkeni de ilgili şahsın doğum tarihini alır. Buradaki adres_listesi bileşik bir değişken olup, bir kişi hakkındaki bütün bilgileri saklar.
 

arago_W&B

Üye
1 Mar 2008
139
3
  1. Daha sonra aranan kişinin doğum tarihini Date değişkenine atar. Bir sonraki alt hedefte tamsayıyla gösterilen bugünkü ay ve kişinin doğum tarihi dogum_gununu_kontrol_et yüklemine iletilir.
  2. dogum_gununu_kontrol_et yüklemi iki değişkenle birlikte çağrılır. İlk değişken bir tamsayıya, ikincisi ise dogum_tarihi’ne bağlanır. dogum_gununu_kontrol_et kuralını tanımlayan kuralın baş kısmındaki Bu_ay Mon değişkenine atanır. İkinci argüman olan Date ise dogum_tarihi(Ay, _,_) cümleciğine atanır. Sadece bugünkü tarihten ay ile ilgilendiğimiz için, gün ve yıl için anonim değişkenler kullanılmıştır.
  3. dogum_gununu_kontrol_et yüklemi ayın sembolik değerini tam sayıya dönüştürür ve bu değeri sistemden okunan ay değeri ile karşılaştırır. Karşılaştırmanın başarılı olması durumunda bir sonraki alt hedefe geçer. Karşılaştırma başarısız olursa geriye iz sürme işlemi başlar.
  4. İşlenmesi gereken bir sonraki alt hedef adini_yaz’dır. İstenilen bilgi, doğum tarihi bu ay olan kişinin ismi olduğu için, ekrana bu kişinin adı ve soyadı yazılır. Bir sonraki cümle ‘fail’ olduğu için otomatik olarak geriye iz sürme işlemi başlar.
  5. Geriye iz sürme daima en son kullanılan non-deterministic yükleme geri gider. Bizim programımızda zaten non-deterministic bir yüklem bulunduğu için işlem hemen adres_listesi’ne gider. Program burada işleme konmak üzere başka bir isim aramak için veritabanına gider. Eğer veritabanında işleme konacak başka biri kişi yoksa işlemdeki cümle başarısız olur. Prolog, veritabanındaki diğer satırları inceler ve dogum_gununu_kontrol_et kuralını tanımlayan başka bir cümle bulur.
5.6. Bileşik Nesnelerin Tiplerini Tanımlamak

Bu bölümde bileşik nesne tiplerinin nasıl tanımlanacağı üzerinde duralım.
sahiptir(ahmet, kitap(“Pascal 7”, “Ömer AKGÖBEK”))
sahiptir(ahmet, at(firtina)).
şeklinde tanımlanan ilişkiler
GOAL sahiptir(ahmet, Ne)
sorgusuyla irdelenirse Ne değişkeni iki ayrı argüman ile eşleşebilir. Bunlardani biri kitap, diğeri ise at’tır. Sahiptir yüklemi artık sahiptir(symbol, symbol) şeklinde tanımlanamaz. İkinci argüman symbol tipindeki nesnelere işaret etmez. Bunun yerine
sahiptir(isim, esyalar)
şeklinde bir yüklem tanımlamak mümkündür. Tipleri tanımlarken
Domains
esyalar= kitap(kitap_adi, yazar); at(atin_adi)
kitap_adi, yazar, atin_adi = symbol
yazılabilir.
Yukarıdaki ‘;’ işareti ‘veya’ anlamına gelir. Bu durumda iki alternatiften bahsetmek mümkündür. Bir kitap, kitabın adı ve yazarının adıyla, bir ‘at’ ise sadece ismiyle tanımlanabilir. Kitap_adi, yazar, atin_adi değişkenlerinin tamamı symbol tipindedir.
Tip tanımlanmasına daha fazla alternatif rahatlıkla ilave edilebilir.
Örnek
DOMAINS
esyalar= kitap(kitap_ismi, yazar); at(atin_adi); araba; banka_hesabi(nakit)
kitap_ismi, yazar, atin_adi=symbol
nakit = real
isim=symbol
PREDICATES
nondeterm sahiptir(isim, esyalar)
CLAUSES
sahiptir(ahmet, kitap("Pascal 7.0", "Ömer AKGÖBEK")).
sahiptir(ahmet, at(firtina)).
sahiptir(ahmet, araba).
sahiptir(ahmet, banka_hesabi(1000)).
GOAL sahiptir(Kim, Sahip_oldugu_esyalar).
Programı derlenip çalıştırıldığında
Sahip_oldugu_esyalar=kitap(“Pascal 7.0”, “Ömer AKGÖBEK”)).
Sahip_oldugu_esyalar=at(firtina)).
Sahip_oldugu_esyalar=araba
Sahip_oldugu_esyalar= banka_hesabi(1000)).
4 Solutions
cevabı görüntülenir.
5.7. Tip Tanımlamaları Üzerine Kısa Bir Özet

Bileşik nesnelerin tip tanımları genel bir şekilde gösterilecek olursa:
Domain= alternatif1(Tip, Tip, ......); alternatif2(Tip, Tip, .....)
Burada alternatif1 ve alternatif2 farklı operatörlerdir. (Tip, Tip, ...) gösterimi standart veya başka yerde ayrıca tanımlanan symbol, integer, real vs. gibi tip isimlerdir.
Not:
  1. Alternatifler birbirinden daima ‘;’ ile ayrılırlar.
  2. Her alternatif bir operatör ve bu argümana ait tip tanımlarını içerir.
  3. Eğer operatörde herhangi bir argüman kullanılmazsa, bunu alternatifN veya alternatifN( ) biçiminde yazılabilir.
5.8. Çoklu-Düzey Bileşik Nesneler

Prolog’da, birden fazla dereceden oluşan bileşik nesne kullanmak mümkündür. Örneğin
kitap(“Atatürk: Bir Milletin Yeniden Doğuşu”, “Kinross”)
olgusundaki ‘Kinross’ soyismi yerine, yazarın adını ve soyadını ayrıntılı olarak gösteren bir yapı kullanmak mümkündür.
kitap(“Atatürk: Bir Milletin Yeniden Doğuşu”, yazar(“Lord”, “Kinross”))
Daha önceden yapılan tip tanımında
kitap(kitap_adi, yazar)
yazılıyordu. İkinci argüman olan yazar, operatör durumundadır. Fakat yazar=symbol sadece bir isimi kapsadığından, yetersiz kalır. Bu durumda yazar değişkeninin de bileşik nesne olarak tanımlanması gerekir. Bunu da:
yazar=yazar(isim, soyisim)
şeklinde tanımlamak mümkündür. Şimdi tip tanımlarına geçelim.
Domains
esyalar=kitap(kitap_adi, yazar); /*İlk derece*/
yazar=yazar(adi, soyadi) /*ikinci derece*/
kitap_adi, isim, soyisim=symbol /*Üçüncü derece*/
Birden fazla dereceden oluşan bileşik nesneler kullanırken, ağaç biçiminde bir yapı kullanmak büyük kolaylık sağlar.
Kitap​
Kitap_adi yazar​
İsim, soyisim​
Tip tanımı yapılırken bir anda ağaç yapısının sadece bir derecesi kullanılabilir. Örneğin
kitap=kitap(kitap_adi, yazar(adi, soyadi))
Şeklindeki tip tanımı yanlıştır.
5.9. Çoklu-Tipli Argümanlar

Bir yüklemin farklı tiplerde bilgi verebilmesi için bir operatör tanımının yapılması yapmamız gerekir. Aşağıdaki örnekte sizin_yasiniz cümleciği yas argümanını kabul edilmektedir. Yas argümanı ise string, real veya integer olabilir.
DomaIns
yas=i(integer); r(real); s(string)
Predicates
siniz_yasiniz(yas)
CLAUSES
sizin_yasiniz(i(Yas)):-write(Yas).
sizin_yasiniz(r(Yas)):-write(Yas).
sizin_yasiniz(s(Yas)):-write(Yas).
5.10. Listeler

Öğretim üyelerinin verdikleri dersleri liste halinde saklamak istediğimizi kabul edelim. Bunun için aşağıdaki kodun yazılması yeterlidir.
PREDICATES
profesor(symbol, symbol,symbol) /*Adı, soyadı ve verdiği ders*/
CLAUSES
profesor(asaf, varol, bilgisayar).
profesor(ali, erdogan, betonarme).
profesor(ahmet, aydogan, fizik).
Bu tür bir programda, bütün hocaların isimlerini ve verdikleri dersleri tek tek sıralamak mümkündür. Her hoca için ayrı bir olguyu veritabanına ilave etmek gerekir. Kolay görünen bu işin yüzlerce öğretim üyesi olan bir üniversite için yapıldığında ne kadar zor olduğunu açıktır. Prolog’daki liste bir veya daha fazla değer alabilir ve benzer işlerde büyük kolaylıklar sağlar. Bir listedeki değişkenlerin aldıkları değerleri ‘[]’ arasında yazmak gerekir.
DOMAINS
dersler=symbol*
PREDICATES
profesor(symbol, symbol, dersler)
CLAUSES
profesor(asaf, varol, [bilgisayar, termodinamik, iklimlendirme]).
profesor(ali, erdogan, [betonarme, statik, malzeme]).
profesor(ahmet, aydogan, (fizik, matematik, kimya]).
Şeklindeki satırlarda dersler liste tipinde bir değişken olarak tanımlanmıştır. Buradaki ‘*’ sembolü dersler değişkeninin liste tipinde olacağını gösterir. Aynı biçimde, listenin tamsayılardan oluştuğu bir değişken tipi
Domains
tamsayilar_listesi=integer*
şeklinde tanımlanabilir.
Örnek:
DOMAINS
notlar=integer*
PREDICATES
nondeterm sinav_sonuclari(symbol, symbol, notlar)
CLAUSES
sinav_sonuclari(orhan, aydin, [78, 98, 100]).
sinav_sonuclari(kasim, yenigun, [45, 54, 60]).
sinav_sonuclari(husamettin, bulut, [80, 90, 95]).
sinav_sonuclari(huseyin, karasu, []).
GOAL sinav_sonuclari(orhan,_,Aldigi_Notlar).
Programı çalıştırıldığında Orhan’ın aldığı notlar görüntülenir.
6. TEKRARLAMA VE REKÜRSİYON

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.
6.1. 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.
 

arago_W&B

Üye
1 Mar 2008
139
3
6.2. 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.
Ö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.
Ö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.
6.3. Ö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. İkinci 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.
GOAL ulke_adlarini_yaz.
İ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 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.
6.4. 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.
Harf’e değer atayan readchar(Harf) yükleminin öncesine geriye dönüş yapıldığı anda, Harf değişkeni serbest hale gelir. Değişken değerinin kaybolması geriye dönüş işlemi sayesinde alternatif çözümler elde etmek için çok önemlidir. Fakat geriye dönüş işlemi başka bir iş için kullanılamaz. Çünkü geriye dönüş işlemi alternatif ararken, işlemleri birçok kez tekrar edebilir. Fakat bu tekrarlar sırasında bir tekrardan diğerine geçişte hiçbir şey hatırlayamaz. Daha önce de söylediğimiz gibi, işlemlerden sonra değer ataması yapılan değişkenlerin tamamı, geriye dönüş işlemi sırasında bütün bu değerleri kaybederler. Böyle bir döngüde sayaç gibi bir şey kullanıp toplam, kayıt sayısı vs. gibi bir değeri tutmanın kolay bir yolu yoktur.
6.5. Rekursif Prosedürler

Tekrarlama işlemin yapmanın diğer bir yolu da rekursiyondur. Kendisini çağırabilen prosedüre rekursiv prosedür diyoruz. Rekursiv prosedürler çalışırken yaptıkları işlerin sayısını, toplamını veya işlemlerin ara sonuçlarını saklayabilir ve bunları bir döngüden diğerine rahatlıkla aktarabilirler.
Örnek:
N sayısının faktoriyelini hesaplamak için
1. Eğer N=1 ise, faktoriyel=1
2. Diğer durumlarda N-1’in faktoriyelini bul ve bunu N ile çarp
şeklindeki emirleri anlayıp uygulayan bir program yazalım. Örneğin 3 sayısının faktöriyelini bulmak için 2’nin faktöriyelini, 2’nin faktöriyelini bulmak için de 1’in faktöriyelini bulmamız gerekir. 1’in faktöryeli zaten bilindiğinden yapılması gereken tek şey 2 ve 1’in faktöriyellerini N sayısı olan 3 ile çarpmaktır. Görüldüğü gibi
 

arago_W&B

Üye
1 Mar 2008
139
3
asından ibarettir. Daha sonra işlem, prosedürün baş kısmına gider. Prosedürel olarak bu olay bir döngüdeki kontrol değerlerinin yenilenmesine benzer.
Bu işlemlere sondan rekursiyon optimizasyonu veya son-çağrı optimizasyonu adı verilmektedir.
6.5.3. Sondan Rekursiyonun Kullanımı

Prologda bir prosedürün başka bir prosedürü ‘kendisinin en son adımı olarak çağırmasının’ ne anlama geldi konusu incelenecektir.
  1. Çağrı, cümlenin en son alt hedefidir.
  2. Bu cümlenin ilk kısımlarında geriye dönüş noktaları yoktur.
Aşağıdaki örnek bu iki şartı sağlamaktadır:
sayac(Sayi):-
write(Sayi), nl,
yeni_sayi=Sayi+1,
sayac(Yeni_sayi)işlemler burada sonsuza kadar gitmemektedir. Şimdi bunları Prolog ile ifade etmeye çalışalım:
PREDICATES
faktoriyel(unsigned, real)
CLAUSES
faktoriyel (1, 1):-!.
faktoriyel (X, Faktoriyel_X):-
Y=X-1,
faktoriyel(Y, Faktoriyal_Y),
Faktoriyel_X=X*Faktoriyal_Y.
GOAL X=6, faktoriyel(X, Faktoriyel).
Programı 6 sayısının faktöriyelini bulur.
Burada ilginç bir durum vardır. Bilgisayar faktöriyel işleminin yarısında iken nasıl olur da faktöriyeli hesaplar? Faktöriyel kuralını X=6 olacak şekilde çağırılırsa, faktöriyel kendini X=5 için çağırılacaktır. Bu durumda X değeri 6 mı olacak 5 mi?
Cevap şudur: Bilgisayar faktöriyel prosedürünün bir kopyasını oluşturur ve bu kopyayı çağır. Kopyanın kendini faktoriyel prosedürünün aynısıymış gibi çalışır. Sadece argümanların ve değişkenlerin kopyalarına ihtiyaç duyulur.
Bu bilgi yığın olarak hafızada saklanır ve bir kural çağrıldığında her seferinde yeniden oluşturulur. Kural non-deterministic değil ise sona erdiği zaman bellek yığını sıfırlanır.
6.5.1. Rekursiyonun Avantajları

  • Başka türlü güvenli bir şekilde ifade edilemeyen algoritmaları daha açık bir şekilde ifade edebilir.
  • Mantıksal olarak iterasyondan çok daha basittir.
  • Listeleri işlemede çok yaygın olarak kullanılır.
Rekursiyon işlemi özellikle problem 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.
6.5.2. Sondan Rekursiyon 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 prosedürün yapması gereken işlem bittiği zaman, çağrıyı yapan prosedür kaldığı yerden işleme devam edebilir. Bunun dezavantajı şudur: Örneğin bir prosedür kendisini 100 defa çağırırsa, her seferki durum kaydedileceği için tam olarak 100 değişik durum hafızaya alınmış olur. Hafızaya alınan her duruma stack frame (yığın alanı) denir. 16 bitlik PC DOS sisteminde bu alan 64K ile sınırlı olup, ancak 3000-4000 yığın alacak kapasitedir. 32 Bit’lik sistemlerde teorik olarak bu alan GB düzeyine kadar çıkabilir, fakat bu kez de başka engeller ortaya çıkar. Yığın alanın azaltmak için ne yapılabilir?
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 şey kalmaz. Çağrıyı yapan prosedürün kendisin ç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.
B prosedürünün C’yi çağırmak yerine, kendisini işlemin en son adımı olarak çağırdığını düşünelim. B prosedürü yine B’yi çağırdığı zaman, çağrıyı yapan B’nin yığın bilgisi, çağrılan B’nin yığın bilgisi ile yer değiştirilmelidir. Bu ise çok basit bir işlemden yani argümanların yeni değerleri alm.
İşte bu prosedür sondan rekursif bir prosedürdür ve hafızada yeni bir yığına neden olmaksızın kendisini çağırır. Dolayısıyla hafızayı tüketmez. Bu programa GOAL sayac(0) değeri verilse, 0 ile başlayan tam sayılar yazılmaya başlanır ve işlem bitmez.
Örnek:
PREDICATES
sayac(ulong)
CLAUSES
sayac(Sayi):-
write('\r',Sayi),
Yeni_sayi=Sayi+1,
sayac(Yeni_sayi).
GOAL nl, sayac(0).
Bu programa GOAL sayac(0) ile çalıştırılırsa, 0’dan başlamak üzere tam sayılar yazılmaya başlanır ve işlem bitmez.
6.5.3. Sondan Rekursiyonu Engelleme

  1. Eğer rekursiv çağrı en son adım değilse, prosedür sondan rekursiv değildir. Örneğin;
PREDICATES
rakam_yaz(ulong)
CLAUSES
rakam_yaz(Sayi):-
write('\r', Sayi),
Yeni_sayi=Sayi+1,
rakam_yaz(Yeni_sayi), nl.
Goal nl, rakam_yaz(0).
Rakam_say prosedürü kendisini çağırdında, kontrolün yeniden rakam_say(Sayi) dönmesi için hafızada bir yığın kaydedilir. Çünkü son alt hedef ‘nl’dir ve bunun işleme girmesi gerekir. Dolayısıyla döngü bir süre sonra hata mesajı vererek durur.
2. Sondan rekursiyonu engellemenin bir diğer yolu da rekursiyonun yapıldığı anda, geriye henüz denenmemiş bir alternatifin kalmasıdır. Bu durumda prosedürün son durumunun kaydedilmesi gerekir. Çünkü rekürsiv çağrının başarısız olması durumunda çağrıyı yapan prosedürün geriye gidip denenmemiş bir alternatifi deneyebilmesi gerekir.
Örnek:
Clauses
rakam_yaz(Sayi):-
write('\r', Sayi),
Yeni_sayi=Sayi+1,
rakam_yaz(Yeni_sayi).
rakam_yaz(Sayi):-
Sayi<0, write(“Sayi sıfırdan küçüktür.”).
GOAL rakam_yaz(0).
Burada rakam_yaz cümlesi, ikinci cümle denenmeden önce kendisini çağırır. Program yine bir süre sonra hafıza tükenmesinden dolayı durur.
 

arago_W&B

Üye
1 Mar 2008
139
3
  1. Denenmemiş alternatifin rekursiv prosedürün kendisi için ayrı bir cümle olması gerekmez. Rekürsiv prosedürün çağırdığı başka bir cümlede bir alternatif de olabilir. Örnek:
rakam_yaz(Sayi):-
write('\r', Sayi),
Yeni_sayi=Sayi+1,
Kontrol_et(Yeni_sayi).
rakam_yaz(Yeni_sayi).
Kontrol_et (Z):-Z>=0.
Kontrol_et (Z):- Z<0.
Sayi değişkeninin değeri normalde pozitiftir. Bu durumda rakam_yaz her ne zaman kendisini çağırsa, kontrol_et yükleminin ilki doğrulanır, fakat ikinci kontrol_et yüklemin henüz doğrulanmamış durumdadır. Bu yüzden rakam_yaz yüklemi, geriye dönüş işlemi sırasında kontrol etmek üzere yığın bölgesine bir kopya almak zorundadır.
PREDICATES
yanlis_sayac1(long)
yanlis_sayac2(long)
yanlis_sayac3(long)
kontrol_et(long)
CLAUSES
/* Rakam_yaz: Rekursiv çağrı son adım değildir.*/
yanlis_sayac1(Sayi):-
write ('\r', Sayi),
Yeni_sayi=Sayi+1,
yanlis_sayac1(Yeni_sayi), nl.
/* Rakam_yaz2: Rekursiv çağrı yapıldığı anda henüz denenmemiş bir clause var.*/
yanlis_sayac2(Sayi):-
write ('\r', Sayi),
Yeni_sayi=Sayi+1,
yanlis_sayac2(Yeni_sayi).
yanlis_sayac2(Sayi):-
Sayi<0,
write ("Sayı negatiftir.").
/* Rakam_yaz3: Rekursiv çağrıdan önce çağrılan yüklemde denenmemiş bir alternatif var.*/
yanlis_sayac3(Sayi):-
write ('\r', Sayi),
Yeni_sayi=Sayi+1,
kontrol_et(Yeni_sayi),
yanlis_sayac3(Yeni_sayi).
kontrol_et(Z):-
Z>=0.
kontrol_et(Z):-
Z<0.
GOAL yanlis_sayac1(1458).
6.6. Rekursiyonda Cut Kullanımı

Bir prosedürün sondan rekürsiyonlu olup olmadığından kesin olarak emin olunamayacağı düşünülebilir. Rekursiv olan çağrıyı, son cümleciğin en son alt hedefi yaparak, bu problemi çözmek mümkündür. Fakat yine de hedef cümlesinin çağıracağı diğer prosedürler arasında denenmemiş başka bir alternatif olmadığını nasıl garantiye alabiliriz?
Bunu garantiye almak gerekmez, çünkü ‘!’ yani Cut komutunu kullanarak bulunabilecek bütün alternatiflerin önünü kesmek mümkündür. Cut komutunun anlamı şöyleydi. Goal cümleciği ile belirlenen yükleme uygun çözüm ararken, gelinen nokta bizim aradığımız noktadır. Artık öteye gitmeye gerek bulunmamaktadır. Alternatifler de ortadan kalktığı için, artık hafızada yığın oluşturmaya gerek kalmaz.
Yukarıdaki örnekte görülen rakam_say cümlesini, şöyle düzeltmek mümkündür (İşlemdeki ismini değiştirelim):
Cut_sayaci3(Sayi):-
Write (‘\r’, Sayi),
Yeni_sayi=sayi+1,
Kontrol_et(Yeni_sayi), !, cut_sayaci3(Yeni_sayi).
Cut komutu yanlis_sayac2 cümleciğinde aynı şekilde etkili olur. Çünkü testi negatife düşürüp ikinci cümlecikten birinciye taşır.
Cut_sayaci2(Sayi):-
Sayi>=0, !,
Write (‘\r’, Sayi),
Yeni_sayi=Sayi+1,
cut_sayaci2(Yeni_sayi).
Cut_sayaci2(Sayi):- write (“Sayi negatiftir.”).
Cut komutunu non-deterministic olan, yani birden fazla çözüm sağlayan yüklemlerle çalışırken, alınan bilginin yeterli olduğuna inanıldığı anda rahatlıkla kullanılabilir.
Aynı şey yanlis_sayac3 için de geçerlidir. Kontrol_et yüklemi işaretine bağlı olarak Sayi üzerinde biraz daha işlem yapılmasını gerektiren bir durumu göstermektedir. Fakat kontrol_et kodu non-deterministic olduğu için Cut komutu iyi bir çözümdür. Kontrol_et yüklemi şöyle yazılabilir:
Kontrol_et(Z):- Z>=0, !, /* Z’yi kullanarak işlem yapmak*/
Kontrol_et(Z):-......
Cut komutu kullanıldığı zaman bilgisayar denenmemiş bir alternatifin kalmadığına karar verir ve bu yüzden de yığın oluşturma yoluna gitmez. Aşağıdaki programda yanlis_sayac2 ve yanlis_sayac3’ün düzeltilmiş hali vardır.
PREDICATES
cut_sayaci2(long)
cut_sayaci3(long)
nondeterm kontrol_et(long)
CLAUSES
/* Rekursiv çağrı yapıldığı anda henüz denenmemiş bir seçenek var*/
cut_sayaci2(Sayi):-
Sayi>=0, !,
write('\r', Sayi),
Yeni_sayi=Sayi+1,
cut_sayaci2(Yeni_sayi).
cut_sayaci2(_):-
write("Sayi negatiftir.").
/* Rekursiv çağrıdan önceki cümlecikte henüz denenmemiş bir seçenek var*/
cut_sayaci3(Sayi):- write('\r', Sayi),
Yeni_sayi=Sayi+1,
kontrol_et(Yeni_sayi), !, cut_sayaci3(Yeni_sayi).
kontrol_et(Z):-Z>=0.
kontrol_et(Z):-Z<0.
GOAL cut_sayaci3(214).
6.7. Argümanların Döngü Değişkeni Olarak Kullanımı

Rukursiyon bölümünde verilen bir sayının faktöriyelini hesaplayan bir program geliştirilmişti. Bu durum Pascal’da şöyle ifade edilebilir:
P:=1;
For I:=1 to N do P:= P*I;
FactN:=P;
N, faktöriyeli hesaplancak olan sayı, FactN, N sayısının faktöriyeli, I değeri 1’den N’e kadar değişen döngü değişkeni ve P ise ara sayıların değerlerinin toplandığı değişkendir.
Bu programı Prolog’a aktarırken yapılması gereken ilk şey, for komutu için daha basit bir döngü kurmak ve her adımda I değişkenine ne olduğunu daha açık şekilde göstermektir. Program while ile, aşağıdaki biçimde yazılır.
P:=1; /* P ve I değişkenlerine ilk değeri ata.*/
I:=1;
While I<= N do /* Döngü kontrolü*/
Begin
P:=P*I; /*P ve I değişkenlerine yeni değerleri ata*/
 

arago_W&B

Üye
1 Mar 2008
139
3
I:=I+1;
End;
FactN:=P; /* Sayının Faktöriyelini Yaz..*/
Aynı program Prolog ile aşağıdaki gibi yazılır.
PREDICATES
faktoriyel(unsigned, real)
carpanlarin_faktoriyeli(unsigned, long, unsigned, long)
CLAUSES
faktoriyel(Sayi, Sayinin_Faktoriyeli):-
carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, 1, 1).
carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, I,P):-
I<=Sayi, !,
Yeni_P=P*I,
Yeni_I=I+1,
carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, Yeni_I, Yeni_P).
carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, I, P):-
I>Sayi,
Sayinin_faktoriyeli=P.
GOAL faktoriyel(5, Sayinin_Faktoriyeli).
Programın ayrıntıları aşağıda verilmiştir.
Faktoriyel cümleciğinin Sayi ve Sayinin_Faktoriyeli olmak üzere iki değişkeni vardır. Bunlardan sayı, faktöriyeli bulunacak sayı, diğeri ise bu sayının faktöriyelidir. Rekursiyon işlemi aslında carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, I, P) cümlesinden meydana gelir. Bu cümledeki 4 değişkenin bir adımdan diğerine aktarılması zorunludur. Bu yüzden faktoriyel sadece carpanlarin_faktoriyeli yüklemini harekete geçirir ve sayı, sayının faktöriyeli, I ve P’nin ilk değerlerini buraya aktarır. Böylece
faktoriyel(Sayi, Sayinin_Faktoriyeli):-
carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, 1, 1).
sayesinde I ve P değişkenleri ilk değerlerini almış olurlar. Burada dikkat çeken şey, faktoriyel yükleminin hiçbir değeri olmayan Sayinin_faktoriyeli değerini carpanlarin_faktoriyeli yüklemindeki sayinin_faktoriyeli değişkenine aktarmasıdır. Prologun yaptığı tek şey, iki cümlede bulunan Sayinin_faktoriyeli değişkenlerini eşleştirmektir. Aynı şey carpanlarin_faktoriyel’i yüklemindeki sayinin_faktoriyeli değişkeninin rekursiv çağrı esnasında kendisine atanmasında da olur. Son aşamada ise Sayinin_faktoriyeli bir değer alacaktır. Bu değeri aldığı zaman daha önceki bütün sayinin_faktoriyeli değişkeni aynı değeri alır. Gerçekte ise sayinin_faktoriyeli değişkeninin bir değeri vardır. Çünkü Sayinin_faktoriyeli değişkeni, ikinci cümledeki carpanlarin_faktoriyeli cümlesinden önce hiçbir zaman gerçek anlamda kullanılmaz.
Şimdi carpanlarin_faktoriyeli yüklemine gelelim. Bu yüklem, döngünün devam şartı olan I sayısının Sayi’dan az veya eşit olup olmadığını kontrol eder. Daha sonra Yeni_I ve Yeni_P değerleriyle kendisini rekursiv olarak çağırır. Burada Prolog’un başka bir özelliği ortaya çıkmaktadır. Diğer dillerin çoğunda mevcut olan
P=P+1
şeklindeki bir ifade Prolog’da yanlıştır. Bu yüzden Prolog’da bir değişkenin değerini değiştirmek mümkün değildir. Bunun yerine
Yeni_P=P+1
şeklinde bir ifade kullanmak gerekir. Bu durumda ilk cümlecik
carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, I,P):-
I<=Sayi, !,
Yeni_P=P*I,
Yeni_I=I+1,
carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, Yeni_I, Yeni_P).
şeklinde yazılabilir. Buradaki Cut komutu, cümlecik yüklemde en sonda olmasa da, son çağrı optimizasyonuna imkan tanır. Zamanla I değişkeninin değeri Sayi değişkeninin değerine geçer. Bu durumda işlem P’nin o anki değerini sayinin_faktoriyeli ile eşleştirir ve rekursiyonu bitirir. Bu nokta ikinci cümlede, yani birinci cümledeki I<=Sayi testinin yanlış çıktığı zaman meydana gelecektir.
carpanlarin_faktoriyeli(Sayi, Sayinin_faktoriyeli, I, P):- I>Sayi, sayinin_faktoriyeli=P.
haline dönüşür. Sayinin_faktoriyeli=P ifadesinin ayrı bir satırda olması gerekmez. Çünkü sayinin_faktoriyeli değişkeninin yerine P değişkenini yazarak değer ataması yapılabilir. Ayrıca I>Sayi testi de gereksizdir, çünkü bunun tersi zaten birinci cümlede denenmiş olmaktadır. Bunun son hali:
carpanlarin_faktoriyeli(_, Sayinin_faktoriyeli,_, Sayinin_Faktoriyeli) olur.
PREDICATES
faktoriyel(unsigned,real)
faktoriyel(unsigned,real,unsigned,real)
CLAUSES
faktoriyel(Sayi, Sayinin_faktoriyeli):-
faktoriyel(Sayi, Sayinin_faktoriyeli,1,1).
faktoriyel(Sayi, Sayinin_faktoriyeli, Sayi, Sayinin_faktoriyeli):-!.
faktoriyel(Sayi, Sayinin_faktoriyeli,I,P):-
Yeni_I = I+1,
Yeni_P = P*Yeni_I,
faktoriyel(Sayi, Sayinin_faktoriyeli, Yeni_I, Yeni_P).
GOAL faktoriyel(12, Sayinin_Faktoriyeli).
 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.