24 Ocak 2017 Salı

Red Temel Bilgiler

Bir önceki yazımızda Red programlama diline kısa bir giriş yapmıştık. Şimdi de dilin temel yapılarına derinlemesine bir girelim. 

Fonksiyonlar

Fonksiyonlar verilen argümanlar (ya da parametreler) doğrultusunda eylem yapan kelimelerdir. Örneğin "print" fonksiyonu Red konsolda argümanda verilen değeri yazar. Aşağıdaki kodda "print" kelimesi fonksiyon, çift tırnak içinde yazılmış olan "Merhaba Dünya!" yazısı da argümandır. Şimdi Red konsolda şu kodu yazalım:
print "Merhaba Dünya!"

"halt" fonksiyonu hiçbir argüman almaz, sadece programın çalışmasını durdurur ve konsolu gösterir:
halt
"request-file" fonksiyonu bir diyalog penceresi açarak kullanıcıdan bir dosya adı seçmesini ister:
request-file
Red'de bazı fonksiyonlar hedef bölgemizi daraltacak filtreleme ilaveleri alabilir. "request-file" fonksiyonu da böyle bir fonksiyon. Aşağıdaki satırları konsolda deneyip sonuçlarını görelim:
request-file/file %test.red
request-file/file/save %test.red

Değer Dönüşleri

"ask" fonksiyonu kullanıcıya bir soru sorar ve cevabını geri döner:
ask "Bir yazı girin :  "
Konsolda çalışırken dönen değer otomatik olarak konsola yazılır. Eğer program içinde çalışıyorsak geri dönen değeri kendimiz "print" fonksiyonu ile yazdırabiliriz:
Red []        ; header, her Red betiğinin başında bulunur
print ask "Bir yazı girin :  "
halt          ; yazdıktan sonra programı kapatır
Aşağıdaki örnek "request-dir" fonksiyonundan dönen değeri kullanıcıya konsolda gösterir:
 print request-dir
Not olarak yukarıdaki kodda "print" fonksiyonu argümanı daha oluşmadığı için, önce "request-dir" fonksiyonu çalışır ve bir değer geri döner, "print" fonksiyonu daha sonra çalışarak bu değeri gösterir.
Red'de bir fonksiyondan geri dönen değeri bir diğer fonksiyona argüman olarak girmek çok kullanılan bir yapıdır.

Veri Kalıcılığı - Red Veritabanına İhtiyaç Duymaz

Bir veriyi harddiske, harici diske ya da herhangi bir saklama ünitesine yazmak için "write" fonksiyonunu kullanırız. "write" fonksiyonu iki argüman alır bir dosya adı ve bu dosyaya saklanacak veri. Dosya adı % işareti öneki alıarak bir dosya adı olduğu Red'e bildirilir. 
write %mydata "Bu daha sonrası için saklamak istediğim bir yazı"
Daha sonra bu sakladığımız yazıyı okumak için "read" fonksiyonunu kullanırız. Dosyadan okunan değeri göstermek için "print" fonksiyonunu ya da formatını değişmeden göstermek için "probe" fonksiyonunu kullanabiliriz:
print read %mydata

probe read %mydata
Yerel sürücülerdeki veriyi okuduğumuz gibi bir network/internet URL adresinden de dosya göstererek veri okuyabiliriz:
read http://site.com/mydata.txt
/binary filtrelemesi ile veriyi byte byte okuyabiliriz:
read/binary http://redprogramming.com/Home.html
"write" ve "read" fonksiyonunu kombine ederek bir download işlemi gerçekleştirebiliriz:
write %r.html read/binary http://redprogramming.com/Home.html
Red'in anlayabildiği herhengi bir karmaşık yapıdaki veriyi saklamak için "save" fonksiyonunu kullanırız:
save %mycontacts ["John" "Bill" "Jane" "Ron" "Sue"]
Saklanan bu veri yapısını geri yüklemek için "load" fonksiyonunu kullanırız:
probe load %mycontacts
Önümüzdeki kısımlarda Red'in tüm bu kalıcı verileri araştırma, sıralama, değiştirme, ekleme, çıkarma vb. kabiliyetlerine sahip olduğunu göreceğiz. Bununla birlikte tüm aynı işlemleri MySQL ya da SQLite gibi veri tabanlarında da yapabildiğini göreceğiz.


Değişkenler

Değişkenler programımız içersinde değişik verileri içine saklayabildiğimiz kelimelerdir. Red'de değişkenler tanımlanırken sonlarına ":" karakteri eklenerek sisteme tanıtılırlar. Aşağıdaki kodu konsolda deneyelim:
name: "Ümit"
probe name
Dikkat edersek değişken değeri okunurken ":" karakteri eklenmiyor, sadece değişkene bir değer verirken kullanılıyor. Değişkenler adından da anlaşılabileceği gibi içerdikleri değerler değişebilir elemanlardır. Mesela aşağıdaki kodda yine aynı değişkene bu sefer başka bir değer veriyoruz:
name: "Belgin"
probe name
Red isimlendirmelerde büyük-küçük harf duyarlığı kullanmaz. Yani değişkenlerin isimlerinde büyük ya da küçük harfler bulunması bişey ifade etmez aşağıda tüm değişken isimleri yazılımı farklı olmasına rağmen Red tarafından aynı değişken olarak algılanır:
name: "George"
print name
print Name
print NAME
print NaMe
Bir değişkene herhangi bir fonksiyondan dönen değeri de koyabiliriz. Bu kod kullanıcının seçtiği dosyanın adını gösterir:
name: request-file
probe name
Değişken içine kalıcı hafızaya daha önce kaydettiğimiz bilgiyi de okuyabiliriz:
data: read %mydata
probe data
Değişken içine bir program parçası da saklayabiliriz. Daha sonra bu program parçacığını "do" fonksiyonu ile çalıştırabiliriz de:
mycode: [print "Merhaba" halt]
do mycode

Koşullu İşlemler

Çoğu programda if/then işlemleri yapmak gerekir. Yani Eğer (bu) doğruysa o zaman (bunu) yap.
bankadaki_para: -10
if bankadaki_para < 0 [print "Senin ekonomi çökmüş."]
"either" koşullaması diğer dillerdeki if/else yapısının yaptığını yapar. Yani Eğer (bu) doğruysa [bunu yap] [değilse bunu yap]. Aşağıdaki örnekte her blok girintili şekilde yazılarak her bloğun ne yaptığının daha net okunması sağlanmıştır. Bir ilave daha aşağıda kod "do[]" çevrimi içine yerleştirilmiştir, niye? konsolda tümü son "]" kapatılınca çalışsın diye:
do [
   pass: ask "Şifreyi Girin:  "
   either pass = "secret" [ 
      print "Ooo Hoşgeldin."
   ] [
      print "Şifreyi Bilmiyorsun."
   ]
]
"case" fonksiyonu da bir blok içinde bir çok olasılığı değerlendirme amaçlı kullanılabilir:
name: "Ümit"
case [
    find name "a" [print {Adınızda "a" harfi var}]
    find name "e" [print {Adınızda "e" harfi var}]
    find name "ı" [print {Adınızda "ı" harfi var}]
    find name "i" [print {Adınızda "i" harfi var}]
    find name "o" [print {Adınızda "o" harfi var}]
    find name "ö" [print {Adınızda "ö" harfi var}]
    find name "u" [print {Adınızda "u" harfi var}]
    find name "ü" [print {Adınızda "ü" harfi var}]
    true [print {Eyvah adınızda sesli harf yok!}]
]
Her satır bir koşulu test eder ve o koşul doğruysa arkasındaki blok program çalışır. Red'de daha bir çok koşullu işlem var ancak bunlar şimdilik bir çok işi görmemize yeterli.

Yazılarla Çalışma ve Birleştirme İşlemleri

İçerisinde tırnak işareti bulunan ya da çok satırdan oluşan yazıları girmek için {süslü parantez} içinde yazabiliriz. 
print {Bana "Merhaba" dedi}

print {
    satır 1
    satır 2
    satır 3
}
"trim" fonksiyonu ile gereksiz boşlukların silinmesi gibi düzeltmeler yapabiliriz:
print trim {
    satır 1
    satır 2
    satır 3
}

print trim/all {
    satır 1
    satır 2
    satır 3
}
"^/" karakteri return tuşunun aynısını yapar:
print "satır 1^/satır 2^/satır 3"
"prin" fonksiyonu ile yazıları sonunda altsatıra geçmeden yazdırabiliriz:
prin "yeni satır yok  " prin "el ile eklemek gerekli" prin newline  ; "^/"
"Concatenation" bir çok verinin birleştirilmesi işlemidir. Red yazıları birleştirmek için "append" fonksiyonunu kullanır:
print append "Seçilen dosyanın adı: " request-file
Birçok program değişkenlerde saklanmış değerlerin birleştirilmesi yoluyla bir sonuç oluşturur. Bu değerler kulanıcı tarafından girilen değerler, koşullu işlem sonucu oluşan değerler ya da benzeri program çalıştıkça değişime uğrayan değerler olabilir. Birleştirilecek elemanlar birçok satırda ve girintili olarak yazılabilir (okunabilirliği artırmak için):
do [
    name: ask "Adınız:  "
    file: request-file
    print append append name ", seçtiğin dosya: " file
]
Birçok değeri yazdırmak istersek birleştirme komutlarına gerek yok, değerleri bir blok içinde verirsek otomatik olarak birleştirilecektir:
name: "Ümit"  birthday: "26-Tem-1966"  phone: "505-550-xxxx"
prin ["Adı: " name  "  Doğumu: " birthday "  Telefonu: " phone]
Program parçacıklarını da yazı gibi birleştirip "do" fonksiyonu ile çalıştırabiliriz (bu metaprogramming'in basit bir şeklidir):
do [
    code: ask {Bir kod girin:  }   ; örneğin, {print "merhaba"}
    do append {print "İşte sizin kodunuzun çalışan hali..."} code
]

Listeler

Bir çok bilgisayar uygulaması veri listeleri ile uğraşır. Bir grafik programında koordinatlar listesi, bir stok programında malzeme listesi fiyatları adetleri vs., bir finans programında kişilerin isimleri telefonları adresleri hesap numaraları, başka bir programda kullanılan dosyaların isimleri gibi. Red'in ana liste yapısı "series" adıyla bilinir. Serileri birleştirmek, yüklemek, kaydetmek gibi birçok işlem yapılabilir. Bir yazı içindeki harfleri işlemek (karakter listesi), bir oyundaki ekran grafiklerini işlemek (bir çizim bloğundaki objeleri ve koordinatlarını işlemek), ağdaki istasyonlar arası transfer edilecek verileri işlemek vs. Tüm bu işlemler bu basit işlemleri birlikte kullanarak oluşur.
Red'de serileri ifade etmek için kullanılan en basit yapı "blok" yapısıdır. Blok oluşturmak için liste elemanları köşeli parantez içinde yazılır ve bir değişkene atanır:
names: ["John" "Dave" "Jane" "Bob" "Sue"]
codes: [2804 9439 2386 9823 4217]
files: [%employees %vendors %contractors %events]
Basit fonksiyonlar ve yapılar kullanılarak bu listelerden eleman seçme, arama yapmak veya sıralama işlemleri yaspılabilir:
print pick names 3          ; bu ilk iki satır
print names/3               ; tamamen aynı işi yapar
print find names "Dave"
print sort names
print sort codes
Dikkat edersek sort işlemi her listeyi içeriğine göre sıralıyor (isimler alfabetik sırayla, sayılar küçükten büyüğe).
Blokları yüklemek ve kaydetmek için "load" ve "save" fonksiyonları kullanırız:
names: ["John" "Dave" "Jane" "Bob" "Sue"]
save %mynames names
loaded-names: load %mynames
probe loaded-names
Serileri işlemeyi iyi öğrenmek Red programlama dilinde çok önemlidir. Bu fonksiyonlar daha önceden programlama yapanlara oldukça tanıdık gelecektir, pick, find, at, index?, length?, append, remove, insert, extract, copy, replace, select, sort, reverse, head, next, back, last, tail, skip, change, poke, clear, join, intersect, difference, exclude, union, unique, empty?, write, read, save, load.

Çevrimler

Çevrimlerle bir liste elemanları üzerinde işlem yapar ya da onları kullanırız. "foreach" bunların en sık kullanılanı:
names: ["John" "Dave" "Jane" "Bob" "Sue"]
foreach name names [print name]
Çoğunlukla liste elemanlarını bir koşula göre işlemek gerekebilir:
names: ["John" "Dave" "Jane" "Bob" "Sue"]
foreach name names [
    if find name "j" [print name]
]

numbers: [323 2498 94321 31 82]
foreach number numbers [
    if number > 300 [print form number]
]
Bir liste içindeki elemanları satırlar ve sütunlar şeklinde işleyebiliriz. Aşağıdaki örnek "mycontacts" listesini ardışık üç eleman olan isim, adres ve telefon olarak değerlendiriyor:
mycontacts: [
    "John Smith" "123 Tomline Lane Forest Hills, NJ" "555-1234"
    "Paul Thompson" "234 Georgetown Pl. Peanut Grove, AL" "555-2345"
    "Jim Persee" "345 Pickles Pike Orange Grove, FL" "555-3456"
    "George Jones" "456 Topforge Court Mountain Creek, CO" ""
    "Tim Paulson" "" "555-5678"
]
foreach [name address phone] mycontacts [
    print name
]
Verinin sütunlarını elde etmek için "foreach" fonksiyonu yerine "extract" fonksiyonu da kullanabiliriz:
mycontacts: [
    "John Smith" "123 Tomline Lane Forest Hills, NJ" "555-1234"
    "Paul Thompson" "234 Georgetown Pl. Peanut Grove, AL" "555-2345"
    "Jim Persee" "345 Pickles Pike Orange Grove, FL" "555-3456"
    "George Jones" "456 Topforge Court Mountain Creek, CO" ""
    "Tim Paulson" "" "555-5678"
]
probe extract mycontacts 3          ; her 3 elemanda bir 
                                    ; (ilk sütunu alır)
probe extract/index mycontacts 3 3  ; her 3 elemanda bir 3.yü alır
                                    ; (3. sütunu alır)
Bir listenin elemamları üzerinden sayarak gitmek için "foreach" fonksiyonu gibi "repeat" fonksiyonu da kullanabiliriz. Bu örnek names bloğunun 1 den sonuncu elemanına kadar i değişkenine değer vererek çevrim içinde i değişkenini her seferinde 1 arttırarak devam eder:
names: ["John" "Dave" "Jane" "Bob" "Sue"]
repeat i (length? names) [
    print append append form i ": " pick names i
]

names: ["John" "Dave" "Jane" "Bob" "Sue"]
repeat i (length? names) [
    print append append pick names i " next: " pick names (i + 1)
]
"forever" fonksiyonu bir "break" kelimesi görene kadar sürekli devam eder:
count: 99
forever [
    print append form count " şişe bira duvarda"
    count: count - 1
    if count = 0 [break]
]

Kullanıcı Arabirimleri


Konsol uygulamaları

Küçük işler gören betikler genelde Red konsol üzerinden veriler alır veya konsolda bir şeyler gösterir. "ask" ve "print" fonksiyonlarını kullanarak basit bir i/o uygulaması yapabiliriz. Aşağıdaki kodu bir dosyaya yazalım ve çalıştıralım (ya da Red konsolda "do %dosyaismi.red" ile çağırabiliriz):
Red []
user: ask "Kullanıcı(iwu83):  "
pass: ask "Şifre(zqo72):  "
either all [user = "iwu83" pass = "zqo72"] [
    print "Tekrar Hoşgeldin"
] [
    print "Kullanıcı ya da Şifre Hatalı"
]
ask ""

GUI (Graphical User Interface) uygulamaları

Birçok uygulama bilgileri göstermek ya da girdileri almak için ekranda grafik gösterimler kullanır. Yazıları göstermek için kutucuklar, program akışını kontrol için butonlar, açılan listeler, checkbox'lar vs. "widget"lar. Red'in GUI oluşturmak için çok basit kodlama teknikleri vardır. "view" kelimesi ekranda bir pencere oluşturur. Arkasından gelen bir blok widget açıklamalarını içerir (pencere üzerindeki tüm görsel elemanlar). "below" ve "across" kelimeleri widget'ların nasıl sıralanacağını belirtir. Aşağıdaki örneklerin herbirini bir ".red" dosyasına yazıp derleyelim ve çalıştırıp üretilen pencereleri görelim:
Red [title: "Test" needs: 'view]
view [
    below
    button
    field
    text "Red gerçekten kolay bir program."
    text-list
    check
]
Herhangi bir widget'ın görüntüsünü ve yerleşimini değişik argümanlar kullanarak belirleyebiliriz:
Red [title: "test" needs: 'view]
view [
    below
    button red "Beni Tıkla"              
    field 400 "Buraya bir şeyler yazın"  
    text font-size 16 "Red gerçekten kolay bir program." purple
    text-list 400x300 data ["satır1" "satır2" "diğer satır"]
    check yellow
]
Bir widget'ın tıklandığında ya da aktif olduğunda bir kod çalıştırmasını sağlamak için tanımının yanına bir kod bloğu ekleriz. Böylece GUI'miz işlem yapmaya başlar:
Red [title: "test" needs: 'view]
view [
    button "Bana tıkla" [print "Butona tıkladın."]
]
Widget'ın içerdiği veriye adının ardına "/" işareti ve veri adını yazarak ulaşabiliriz. Bir widget verisine sonradan ulaşabilmek için tanımlamasında bir değişkene atama yapmak gerekir:
Red [title: "test" needs: 'view]
view [
    below
    text "Bazı eylem örnekleri.  Her widget'ı deneyelim:"
    button red "Beni tıkla" [
        print "Kırmızı butona tıkladın."
    ]
    f: field 400 "Buraya bişeyler yaz ve [Enter] bas" [
        print f/text
    ]
    t: text-list 400x300 data ["Bunu seç" "Sonra bunu" "Şimdi de bunu"][
        print pick t/data t/selected
    ]
    check yellow [print "Sarı check box tıkladın."]
    button "Çıkış" [unview]    
]

Red [title: "test" needs: 'view]
view [
    below
    a: area                               ; a değişkeni bir area widget
    f: field                              ; f değişkeni bir field widget
    across
    button "Göster" [print a/text]
    button "Kaydet" [write %somedatafile.txt a/text]
    button "Yükle" [f/text: read %somedatafile.txt]
]

Red [title: "test" needs: 'view]
view [
    below
    t: text-list data ["1" "2" "3"]                ; t değişkeni bir text-list widget
    button "Seçileni göster" [print pick t/data t/selected]
]
Çevrimler kullanarak pencereleri dinamik olarak da oluşturabiliriz.
Red [title: "test" needs: 'view]
gui: copy []
foreach color [red green blue] [
    append gui reduce ['text color]
]
view layout gui
Yukarıda verilen bilgilerle bir çok GUI uygulaması yapabiliriz. Daha ayrıntılı örnekleri inşallah ileride göreceğiz.

Kullanıcı Tanımlı Fonksiyonlar

"func" kod yapısını kullanarak Red'e kendi fonksiyonlarımızı da tanıtabiliriz. Fonksiyonumuzu ismine atamak için ":" işareti kullanırız. 
Aşağıdaki örnek fonksiyon argümanda verilen değeri 3'le çarpıyor:
triple: func [x] [
    print 3 * x
]
Artık "triple" fonksiyonunu diğer Red fonksiyonları gibi kullanabiliriz:
triple 4
triple 5
triple 6
Fonksiyonumuza argüman göndermeyeceksek "does" yapısını da kullanabiliriz:
cls: does [loop 100 [print newline]]
cls

Değer Dönüşleri

Red fonksiyon tanımlamasında en son işlenen değer fonksiyondan geri dönen değer olur. Aşağıdaki "check" fonksiyonu, kendisine argüman olarak verilen bir dizi yazıyı "list" adında değişkene saklar. Sonra da içinde eksik kelimeler var mı kontrol eder (burada eksik kelimeler "--" karakterleri içerenler olarak belirtiliyor). Bu fonksiyon "answer" değişkenine "bitmiş" değeri vererek başlıyor sonra da "list" içinde "--" karakterleri içeren kelime varsa cevabı "eksik" olarak değiştiriyor. En son satırda da "answer" değişkenini çağırarak fonksiyondan geri dönen değer olmasını sağlıyor:
check: func [list] [
    answer: "bitmiş"
    foreach l list [
        if find l "--" [answer: "eksik"]
    ]
    answer
]
names1: ["Joe" "Dan" "Sh--" "Bill"]
names2: ["Paul" "Tom" "Mike" "John"]
print append "names1 " check names1
print append "names2 " check names2

Kütüphaneler

Kullanışlı fonksiyonlarımızı ana programdan ayrı olarak kütüphanelere saklayıp daha sonra başka yerlerde de kullanabiliriz. Mesela yukarıdaki "check" fonksiyonumuzu "myfunctions.red" dosyasına kaydedip daha sonra ana programımızda "do" ile erişebiliriz:
Red []
check: func [list] [
    answer: "bitmiş"
    foreach l list [
        if find l "--" [answer: "eksik"]
    ]
    answer
]
Şimdi ana programımızı şöyle düzenleyelim:
Red []
do %myfunctions.red
names1: ["Joe" "Dan" "Sh--" "Bill"]
names2: ["Paul" "Tom" "Mike" "John"]
print append "names1 " check names1
print append "names2 " check names2

Hataları Algılamak

"error?" ve "try" fonksiyonları ile programımızın olası hatalarında çalışmasını yönlendirebiliriz. Bir hata olayını algılamak için "if" ya da başka karşılaştırma kullanabiliriz:
if error? try [0 / 0] [print "Sıfıra bölmek hatalıdır"]
Hatayı sistemden de isteyebiliriz:
if error? err: try [0 / 0] [probe err]
"attempt" fonksiyonu da hata algılamakta kullanılabilir:
attempt [1 / 1]
attempt [0 / 0]









Hiç yorum yok:

Yorum Gönder