10 Komple Örnekler

10 Komple Örnekler

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

10.1 Veri-Tanımlama


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