Dille ilgili bu girişi bitirmek üzere Lua'nın farklı imkanlarını gösteren iki tam program göreceğiz. İlk örnek, veri-tanımlama dili olarak Lua kullanımını gösteriyor. İkinci örnek, Practice of Programming kitabından (Addison-Wesley, 1999) Markov zinciri algoritması uygulaması.
Lua web sitesi, dünya çapında Lua'nın kullanıldığı proje tanıtımlarını içeren bir veritabanı tutar. 10.1 listesinde gösterildiği gibi, veritabanındaki her girdiyi otomatik dökümanlaştıran bir tablo kurucuyla temsil ediyoruz. Bu temsille ilgili ilginç olan şey, bu tür girdilerin serisine sahip bir dosyanın, tabloları argüman olarak kullanan bir girdi fonksiyonuna bir dizi çağrı yapan bir Lua programı olmasıdır.
Amacımız, bu verileri HTML olarak gösteren bir program yazmak, bu şekilde veriler web sayfası haline gelir (http://lua-users.org/wiki/LuaUses). Birçok proje olduğundan nihai sayfa ilk önce tüm projelerin başlıklarının bir listesini gösterir ve daha sonra her projenin ayrıntılarını gösterir. 10.2 listesi programın tipik çıktısıdır.
Veri okuması için, program basitçe girdi için uygun bir tanımlama verir ve daha sonra veri dosyasını bir program olarak çalıştırır(dofile ile). Tüm girdileri ilk önce başlık listesi için ve sonra proje ayrıntıları için iki kez dolaşmamız gerektiğini unutmayalım. İlk yaklaşım, tüm girdileri bir dizide toplamak olacaktır. Ancak ikinci çekici bir çözüm var: girdi için herbiri farklı bir tanımlamayla veri dosyasını iki kez çalıştırmak. Bu yaklaşımı devamdaki programda takip ediyoruz.
liste 10.1 Tipik veritabanı girdisi:
girdi = { title = "Tecgraf", org = "Computer Graphics Technology Group, PUC-Rio", url = "http://www.tecgraf.puc-rio.br/", contact = "Waldemar Celes", description = [[ Tecgraf is the result of a partnership between PUC-Rio, the Pontifical Catholic University of Rio de Janeiro, and <a HREF="http://www.petrobras.com.br/">PETROBRAS</a>, the Brazilian Oil Company. Tecgraf is Lua’s birthplace, and the language has been used there since 1993. Currently, more than thirty programmers in Tecgraf use Lua regularly; they have written more than two hundred thousand lines of code, distributed among dozens of final products.]] }
İlk olarak, metni biçimlendirilmiş olarak yazmak için yardımcı bir fonksiyon tanımlarız (bu fonksiyonu bölüm 5.2'de hali hazırda gördük):
function fwrite(fmt, ...) return io.write(string.format(fmt, ...)) end
writeheader fonksiyonu daima aynı olan sayfa başlığını basitçe yazar:
function writeheader() io.write([[ <html> <head><title>Projects using Lua</title></head> <body bgcolor="#FFFFFF"> Here are brief descriptions of some projects around the world that use <a href="home.html">Lua</a>. <br> ]]) end
ilk tanımlama, her projenin başlığını bir liste öğesi olarak yazar. 'o' argümanı girdi tablosu olacak:
function girdi1 (o) count = count + 1 local title = o.title or '(no title)' fwrite('<li><a href="#%d">%s</a>\n', count, title) end
Liste 10.2 Lua projelerini listeleyen tipik bir HTML sayfası:
<html> <head><title>Projects using Lua</title></head> <body bgcolor="#FFFFFF"> Here are brief descriptions of some projects around the world that use <a href="home.html">Lua</a>. <br> <ul> <li><a href="#1">Tecgraf</a> <li> <other entries> </ul> <h3> <a name="1" href="http://www.tecgraf.puc-rio.br/">Tecgraf</a> <br> <small><em>Computer Graphics Technology Group, PUC-Rio</em></small> </h3> Tecgraf is the result of a partnership between ... distributed among dozens of final products.<p> Contact: Waldemar Celes <a name="2"></a><hr> <other entries> </body></html>
Eğer o.title nil ise (yani, tablo alanı sağlanmamış), fonksiyon sabit bir string '(no title)' kullanır.
İkinci tanımlama (Liste 10.3), ilgili proje hakkında ayrıntıları yazar. Tüm öğeler isteğe bağlı olduğu için az birazcık daha karmaşık. (Çift tırnak kullanan HTML ile çakışmayı önlemek için bu programda sadece tek tırnak kullandık.)
Son fonksiyon sayfayı tamamlar:
function writetail() fwrite('/body></html>\n') end
Ana program liste 10.4 de yer almaktadır. Sayfayı başlatır(başlık yazılır), veri dosyasını yükler, başlıkların listesini oluşturmak üzere girdi için ilk tanımlamanın olduğu entry1 çalıştırılır, ardından sayacı(count) sıfırlar ve girdi için ikinci tanımlamanın olduğu girdi2'i çalıştırılır ve nihayetinde sayfayı tamamlar.
Liste 10.3 Tüm girdiyi biçimlendirecek callback fonksiyonu:
function girdi2 (o) count = count + 1 fwrite('<hr>\n<h3>\n') local href = o.url and string.format(' href="%s"', o.url) or '' local title = o.title or o.org or 'org' fwrite('<a name="%d"%s>%s</a>\n', count, href, title) if o.title and o.org then fwrite('<br>\n<small><em>%s</em></small>', o.org) end fwrite('\n</h3>\n') if o.description then fwrite('%s<p>\n', string.gsub(o.description, '\n\n+', '<p>\n')) end if o.email then fwrite('Contact: <a href="mailto:%s">%s</a>\n', o.email, o.contact or o.email) elseif o.contact then fwrite('Contact: %s\n', o.contact) end end
Liste 10.4 Ana program
local inputfile = 'db.lua' writeheader() count = 0 f = loadfile(inputfile) -- veri dosyasını yükle girdi = girdi1 -- ’girdi’ tanımla fwrite('<ul>\n') f() -- veri dosyasını çalıştır fwrite('</ul>\n') count = 0 girdi = girdi2 -- ’girdi’ 'i yeniden tanımla f() -- veri dosyasını tekrar çalıştır writetail()
10.2 Markov Zinciri Algoritması
İkinci örneğimiz Markov zinciri algoritması uygulamasıdır. Program, temel metinde, hangi kelimelerin n önceki kelimelerin bir dizisini takip edebilire dayalı, rastgele metin üretir. Bu uygulama için n değerini 2 varsayacağız.
Programın ilk bölümü temel metni okur ve iki kelimenin her öneki için metindeki bu öneki izleyen kelimelerin bir listesini veren bir tablo oluşturur. Tabloyu oluşturduktan sonra program tabloyu rasgele metin üretmek için kullanır, burada her kelime temel metindekiyle aynı olasılıkla önceki iki kelimeyi izler. Sonuç olarak, çok, ama epey değil, rastgele bir metine sahip oluruz. Örneğin, bu kitabın ingilizce sürümüne uygulandığında, programın çıktısı şunun gibi parçalara sahip olur:
"Constructors can also traverse a table constructor, then the parentheses in the following line does the whole file in a field n to store the contents of each function, but to show its only argument. If you want to find the maximum element in an array can return both the maximum value and continues showing the prompt and running the code. The following words are reserved and cannot be used to convert between degrees and radians.”
Aralarında bir boşluk ile birleştirilen onun iki kelimesiyle her bir önekini kodlayacağız:
function prefix(w1, w2) return w1 .. " " .. w2 end
Önek kelimelerini ilklemek ve metnin sonunu işaretlemek için NOWORD (“\n”) stringini kullanıyoruz. Örneğin, "the more we try the more we do" metni için
tablo
{ ["\n \n"] = {"the"},
["\n the"] = {"more"},
["the more"] = {"we", "we"},
["more we"] = {"try", "do"},
["we try"] = {"the"},
["try the"] = {"more"},
["we do"] = {"\n"},
}
Program statesub değişkeninde tablosunu tutar. Bu tablonun önek listesine yeni bir kelime eklemek için aşağıdaki fonksiyonu kullanırız:
function insert(index, value) local list = statetab[index] if list == nil then statetab[index] = {value} else list[#list + 1] = value end end
İlk olarak, bu önekin hazırda bir listeye sahip olup olmadığını denetler; sahip değilse yeni değerle yeni bir tanesini oluşturur. Aksi takdirde mevcut listenin sonuna yeni değeri ekler.
statetab tablosunu oluşturmak için, okunan son iki kelimeyi tutan w1 ve w2 değişkenlerimiz var. Her yeni kelime okumasında, w1-w2 ile ilişkilendirmiş listeye onu ekler ve sonra w1 ve w2'i güncelleriz.
Tabloyu oluşturduktan sonra, program, MAXGEN kelimeleriyle bir metin üretmeyi başlatır.
İlk olarak, w1 ve w2 değişkenlerini yeniden ilkler. Sonra, her bir önek için, geçerli sıradaki kelimeler listesinden rastgele bir sıradaki kelimeyi seçer, bu kelimeyi yazdırır, ve w1 ve w2'yi günceller. Liste 10.5 ve Liste 10.6 'da programın tamamı gösterilmekte.
Liste 10.5. Markov programı için yardımcı tanımlamalar:
function allwords() local line = io.read() -- mevcut satır local pos = 1 -- satırdaki mevcut posizyon return function() -- iterator fonksiyonu while line do -- satır olduğu sürece tekrarla local s, e = string.find(line, "%w+", pos) if s then -- bir kelime mi buldun? pos = e + 1 -- sonraki pozisyona güncelle return string.sub(line, s, e) -- kelime döndür else line = io.read() -- kelime bulunamadı; sonraki satırı dene pos = 1 -- ilk pozisyondan başlat end end return nil -- artık satır yok: gezinin sonu end end function prefix(w1, w2) return w1 .. " " .. w2 end local statetab = {} function insert(index, value) local list = statetab[index] if list == nil then statetab[index] = {value} else list[#list + 1] = value end end
Liste 10.6. Markov programı:
local N = 2 local MAXGEN = 10000 local NOWORD = "\n" -- tablo oluştur local w1, w2 = NOWORD, NOWORD for w in allwords() do insert(prefix(w1, w2), w) w1 = w2 w2 = w end insert(prefix(w1, w2), NOWORD) -- metni üret w1 = NOWORD w2 = NOWORD -- yeniden ilkle for i = 1, MAXGEN do local list = statetab[prefix(w1, w2)] -- listeden rasgele bir öğe seç local r = math.random(#list) local nextword = list[r] if nextword == NOWORD then return end io.write(nextword, " ") w1 = w2 w2 = nextword end
Hiç yorum yok:
Yorum Gönder