Forum: D Programlama Dili RSS
Bir işlev tasarımının gelişimi
acehreli (Moderatör) #1
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Bir işlev tasarımının gelişimi
Şu konuda erişicilerle aralıkları karşılaştırmıştık:

  http://ddili.org/forum/thread/330

TDPL'de tam bu konuya değinen bir bölüme rastladım. ("The D Programming Language" kitabına biz de kısaca TDPL diyebiliriz herhalde. :))

Yazar, işlevleri anlatmaya 'find' işlevi ile başlıyor. Kitabın o bölümünü burada özetleyeceğim. (Tabii inatla Türkçe kodla. :D)

Bu kitabın zaten programcılık bilenlere yönelik olduğunu konuşmuştuk. Zaten bilinen kavramların D'de nasıl oldukları çok hızlı anlatılıyor. İşlevlerin tanıtımına işe yarar bir 'find' işleviyle başlıyor ve teker teker tasarımı geliştiriyor.

O şekilde tanıtımı çok akıcı bulduğum için aktarmak istedim. Bunların arasında aralık kavramı da kendisini gösteriyor.

Bir dizide arama yapan bir işlev olsun:

bool ara(int[] dizi, int sayı)
{
    foreach (eleman; dizi) {
        if (sayı == eleman) {
            return true;             // bulundu
        }
    }
 
    return false;    // bulunamadı
}
 
void main()
{
    ara([ 10, 1, 42, 5, 7 ], 42);
}

Bulunup bulunmadığını söylemek fazla kullanışlı olmadığı için bulunan elemanın yerini bildirelim. Bulunamazsa yasal olmayan bir indeks döndürür:

int ara(int[] dizi, int sayı)
{
    foreach (i, eleman; dizi) {
        if (sayı == eleman) {
            return i;
        }
    }
 
    return -1;
 
}

İndeks kavramı her veri yapısına uygun değildir; örneğin bağlı listenin belirli bir indeksli elemanına gitmek için baştan adım adım ilerlemek gerekeceği için çok yavaş olur.

Onun yerine erişiciler kullanılabilir (gösterge de olur, çünkü o da erişici olarak kullanılabilir). Ama Phobos aralıklara karar verdiği için yazar işte burada aralık kavramına geçiyor.

Erişici yerine, her tür veri yapısı ile çalışabilecek bir başka bir yöntem gösteriyor: Verilen diziyi başından adım adım tüketelim ve bulduğumuz noktadan geri kalanını döndürelim. Hiç bulamazsak, boş dizi dönmüş olur:

int[] ara(int[] dizi, int sayı)
{
    while ((dizi.length > 0) && (dizi[0] != sayı)) {
        dizi = dizi[1 .. $];    // başından tüket
    }
 
    return dizi;
}

Tabii gerçekten bir "tüketme" olmuyor. Asıl dizi olduğu gibi duruyor. Parametre olarak bir dilim geldiği için, dilimi başından tüketiyoruz. Onun etkisi, dilimi başından daraltmaktır.

Güzel... Ama o işlev kısıtlıdır, çünkü yalnızca int türüyle çalışır. Şablon haline getirerek her türle kullanabiliriz. Şablon yapmak çok kolay: işlev isminden sonra bir (T) ekliyoruz ve int'leri T yapıyoruz.

Her tür olabileceği için, artık "sayı" demek uygun olmaz; onu da "değer" yapalım.

int ve double kullanan bir örnek:

T[] ara(T)(T[] dizi, T değer)
{
    while ((dizi.length > 0) && (dizi[0] != değer)) {
        dizi = dizi[1 .. $];
    }
 
    return dizi;
}
 
import std.stdio;
 
void main()
{
    writeln(ara([ 10, 1, 42, 5, 7 ], 42));   // hem int ile
    writeln(ara([ 1.2, 3.4, 5.6 ], 3.4));    // hem de double ile çalışıyor
}

O işlevde yine de bir sorun var: dizi elemanlarının ve aranan değerin aynı türden olmaları gerekiyor. Örneğin double dizide int aramak istesek çalışmaz.

Onun için iki tane şablon parametresi kullanalım:

// E: dizi elemanlarının türü, A: arananın türü
E[] ara(E, A)(E[] dizi, A değer)
{
    while ((dizi.length > 0) && (dizi[0] != değer)) {
        dizi = dizi[1 .. $];
    }
 
    return dizi;
}

Böylece double dizi içinde int arayabiliriz:

    writeln(ara([ 1.0, 3.0, 5.0 ], 3));

Onun çalışmasının nedeni, işlev içindeki [dizi[0] != değer işleminde solda double, sağda int bulunması, ve bunun yasal bir karşılaştırma olmasıdır.

İşlevin bu halindeki sorun da, artık fazla esnek olmasıdır. :) Karşılaştırılamyan türler bile kullanılsa, derleyici izin verir:

    writeln(ara([ 1.0, 3.0, 5.0 ], "merhaba"));

Evet, bir derleme hatası olur; ama o hata, işlevin uyumsuz parametrelerle çağrıldığı yukarıdaki satıra değil, işlevin içindeki [dizi[0] != değer karşılaştırmasına işaret eder. İyi değil! :) Amaç, derleme hatasının uyumsuz türlerin kullanıldığı "merhaba"lı satıra işaret etmesidir.

O zaman şablon kısıtlaması (template constraint) tanımlarız:

E[] ara(E, A)(E[] dizi, A değer)
    if (is (typeof(dizi[0] != değer) : bool))
{
    while ((dizi.length > 0) && (dizi[0] != değer)) {
        dizi = dizi[1 .. $];
    }
 
    return dizi;
}

Ne yazık ki çok karışık... :/ Oradaki şablon kısıtlaması, o şablonun ancak [dizi[0] != değer karşılaştırmasının sonucunun bool olduğu durumlarda göze alınacağını söyler. Bir anlamda, "bu şablonun çalışabilmesi için bu koşulun gerçekleşmesi gerekir" der.

Yasal olmayan karşılaştırmaların sonucunda is ifadesi 'void' bile olmayan "türsüzlük" üretir ve o da 'bool'a eşit olmaz.

Yukarıdaki kullanımda derleme hatası, artık "merhaba"lı satıra işaret eder.

Bu noktada bir de isimli şablon kısıtlaması tanımlayabiliriz. (Bu adım kitapta yok). Öyle yapınca, şablon kısıtlamasına okunaklı bir isim verilmiş olur:

E[] ara(E, A)(E[] dizi, A değer)
    if (karşılaştırılabilir_mi!(E, A))
{
    while ((dizi.length > 0) && (dizi[0] != değer)) {
        dizi = dizi[1 .. $];    // başından tüket
    }
 
    return dizi;
}

O isimli kısıtlama şöyle tanımlanabilir:

template karşılaştırılabilir_mi(A, B)
{
    const bool karşılaştırılabilir_mi = is (typeof(A.init != B.init) : bool);
}

Tabii bu işlevin birim testinin de en başından beri yazılmış olması gerekiyordu. :) O da şöyle bir şey olabilir:

unittest
{
    // İlk bulunduğu noktadan gerisini vermeli
    assert(ara([ 10, 1, 42, 5, 7, 42 ], 42) == [ 42, 5, 7, 42 ]);
 
    // Bulunamazsa boş dizi dönmeli
    assert(ara([ 10, 1 ], 42) == []);
 
    // double dizide int aranabilmeli
    assert(ara([ 1.0, 3.0, 5.0 ], 3) == [ 3.0, 5.0 ]);
}

Dinlediğiniz için teşekkürler... :)

Ali
canalpay (Moderatör) #2
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Teşekkürler. (Yazıyı okuduğumda ve herşeyi anladıysam yani sadece Teşekkür mesajı yazabiliyorsam o konu hakkında sadece teşekkür mesajı yazayım mı ? Yoksa yazmayım mı ?)
Bu kitabın zaten programcılık bilenlere yönelik olduğunu konuşmuştuk. Zaten bilinen kavramların D'de nasıl oldukları çok hızlı anlatılıyor.

Programcılık bilenlere yönelik derken ne kadar yönelik ? Mesela bir if koşulunu sizin anlattığınız gibi anlatmıyor mu ?

Bu sırada D'yi öğrenirken sanırım ister istemez Aralık ile çalışıyoruz. Erişicilere hiç bulaşmıyoruz ?
acehreli (Moderatör) #3
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
canalpay:
konu hakkında sadece teşekkür mesajı

Bence yazmaya gerek yok ve kendim hiç aramıyorum.

Forumlara ilk takıldığımda bu konuda daha katıydım; acaba ben de şimdi "rica ederim, ne önemi var mı" demeliyim diye düşünürdüm. :) Ama sonradan katılığım geçti. Kendim hiç beklemiyorum ama teşekkürü vermek isteyene de bir şey diyemeyiz tabii...

Daha doğrusu, ben beklemiyor değil, nasıl olsa birisinin işine yarıyordur ve memnun olunuyordur diye düşünüyorum.

Bu kitabın zaten programcılık bilenlere yönelik olduğunu konuşmuştuk. Zaten bilinen kavramların D'de nasıl oldukları çok hızlı anlatılıyor.

Programcılık bilenlere yönelik derken ne kadar yönelik ? Mesela bir if koşulunu sizin anlattığınız gibi anlatmıyor mu ?

Hayır, hic benim anlattığım gibi değil. Çok hızlı başlayan ilk bölümü internette vardı. O bölüm genel olarak tanıtmak içindi.

Ondan sonraki bölümün başlığı "Temel Türler ve İfadeler". Bütün ifadeler madde madde tanıtılıyorlar. Ondan sonraki bölüm, "Deyimler"... Yine, teker teker tanıtılıyorlar. O şekilde ancak bir referans kitabı olabilir. Zaten başka bir şey olduğu da iddia edilmiyor.

while deyiminin anlatıldığı bölümü çevireyim:

TDPL:
3.7 Döngü deyimleri

(Burada döngü kavramının ne olduğu ile ilgili hiçbir açıklama yok. Programlama bilen kimseye açıklayacak bir şey de yoktur zaten.)

3.7.1 while deyimi

Evet, doğru bildiniz:

while (<ifade>) <deyim>

İşlem, <ifade>yi işleterek başlar. Eğer sıfır değilse, <deyim> işletilir ve döngü, tekrar <ifade>nin işletilmesine geçer. Değilse, while deyiminin işi bitmiştir; bir sonraki deyime geçilir.

Hepsi o... Yani söylemek istediğim de o. :) Zaten programlama bilen kişiye while'ı başka ne kadar anlatabiliriz? TDPL öyle bir kitap.

Ama içinde güzel fikirler ve dilin tasarımı konuları da geçiyor. Ama o konular da ileri derece konular.

Örneğin işlevler bölümünde, yalnızca referans türlerini seçen Java gibi dillerdeki "homogeneous translation" ve C++ gibi şablonlu dillerdeki "heterogeneous translation" kavramlarına giriyor. Bunlar dil ve derleyici teknolojilerine ait kavramlar. :) Deneyimli programcıların günlük hayatlarında bile yerleri yoktur.

Özet: TDPL, programcılığa yeni yeni başlayanlara göre değil ama zaten programcılık bilenleri de sıkmaz. Yukarıdaki while bölümü zaten her dilde aynıdır ve o kadarı yeter.

Bu sırada D'yi öğrenirken sanırım ister istemez Aralık ile çalışıyoruz. Erişicilere hiç bulaşmıyoruz ?

Doğru. Erişici eski teknoloji, yaşasın aralıklaaar! :-p

Ama aralıklar da o kadar yeni ki, bütün bilgisayar camiası kabul etmiş değil. Şüphe duyanlar da var. Haklılar da, bugüne kadar erişiciler yetmiş işte diye düşünülebilir.

Ali
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-11-18, 07:42:04 (UTC -08:00)