July 11, 2012

Evet Salih, bahsettiğim tam olarak o şekildeydi. :)

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

July 10, 2012

Bence güzel. front()'lar ref döndürmedikleri için içerideki elemanların değiştirilmelerine de izin vermiyorlar.

~this() içindeki işlemlere hiç gerek olmasa da şu ikisi de derleniyor:

       veri = (int[]).init;
       veri = veri.init;

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 01, 2012

Şimdi ilgili dersi işlerken, Zafer'in başlattığı bu başlıktan çok faydalandım, teşekkürler Zafer.

Bir kaç ekleme yapmak ve soru sormak istiyorum...
Alıntı (zafer:1341406105):

>

Ben opApply içindeki if kontolünden kurtulmak için kodu şöyle düzenlemeye çalıştım. Birde siz bakın nasıl olmuş, bir eksik veya hata var mı? Ne dersiniz ?

>     int opApply(int delegate(ref T) islemler)
>     {
>         int sonuc;
>         for(int i = konum; i >= 0; --i)
>         {
>             sonuc = islemler(yigin[i]);
>         }
>         return sonuc;
>     }
> ```

>
Öncelikle yukarıdaki şekilde değişebilen "konum" değeriyle döngüyü başlatmak soruna sebep oluyor. Çünkü siz herhangi bir anda 'Pop()' üye işlevini çağırdığınızda doğal olarak değişken de değişiyor...:)

Alıntı (acehreli:1341419956):
> opApply() içinde islemler()'in döndürdüğü değere bakmayı unutuyorsunuz. O değer sıfırdan farklı ise bizim kullanıcımız kendi foreach döngüsü içindeyken 'break' demiş demektir. Ona saygı göstermeli ve sonuç sıfırdan farklı olduğunda biz de opApply()'dan çıkmalıyız.
Ayrıca 'if()' sorgusunu kaldırmayı ben de sevdim. Ancak yukarda Ali hocamın bahsettiği şeyi anlayabilmiş değilim. Kaldırmamalı mıydık? Peki bahsedilen **'break'** anı hangi döngü tarafından yapılıyor?

Bu arada anlayabilmek için sınıfı baştan yazdım. Anlamlarındaki derinliği sevdiğim için yine 'push()' ve 'fetch()' üye işlevlerini kullandım. Tabi, yarısında Türkçe ifadeler (konum, bellek vb.) kullanmak çok hoşuma gitmiyor. Oldum mu tam Türkçe veya İngilizce olsun istiyorum! Ama araya imzamız olsun diye Türkçe isimler koymak, hiç de fena değil...:)

class Yığın (T){
private:
size_t konum;
T[] bellek;

this (size_t kapasite) {
bellek.length = kapasite;
}

public:
void push(T)(T veri) {
bellek[konum++] = veri;
//konum++; // Eğer önce artarsa bellek[0] kullanım dışı kalır!
}

T fetch() {
//konum--; // Her manada önce konum eksilmesi gerekli...:)
return bellek[--konum];
}

void rewind() {
konum = bellek.length;
}

bool empty() {
return konum == 0;
}

//* code-toggle-on/off
void popFront() {
--konum;
}

T front() const {
return bellek[konum - 1]; // -1: Range'i, fetch ile uyumlu yapıyor!
}//
int opApply(int delegate(ref T) uygula) {
int index;
for(int i = bellek.length - 1; i >= 0; --i)
{
index = uygula(bellek[i]);
}
return index;
}//
/
}


'** /***(Not: Denemek için her iki kodu kopyalarken aradaki bu yazılanları çıkarmayı ihmal edebilirsiniz!)'
Bu sınıf üzerinde aşağıdaki denemeleri yaptım. Son deneme çıktısını altında verdim. Bu bize 'rewind()' işlevinin neden lazım olabileceğini gösteriyor. Aynı sorun 'for()' ile erişimlerde de göze çarpıyor! Ancak 'opApply()' kullandığınızda, konum değişkeni devre dışı bırakıldığı için böyle bir sorun olmuyor. Bu sefer de 'take()' kullanamıyorsunuz...:(
'** */ **'

import std.stdio;

void main() {
immutable başla = 65; // A harfi ile başlar
immutable sınır = 26; // Z harfi ile biter
/*
with(new Yığın!char(sınır)) {
write("Kuruldu!");
sınır.write("\n\t^---Yüklenen veri adeti / türü--->", typeid(bellek));

   for(char i = başla; i < (başla + sınır) ; i++) push(i);
   // A'dan Z'ye harfler yığına yollandı...
   writeln(" yığın içeriği:");

   do fetch.write("  "); while(!empty);
   rewind();   // Bunu yapmadığımızda alt satır hata verir!
   writeln("\n");
   fetch.writeln("<--Taşma durumunda hata verebilir...\n");

}//*/
auto harf = new Yığın!char(sınır);
for(char i = başla; i < (başla + sınır); i++)
{
harf.push(i);
}
foreach(c; std.range.take(harf, 10)) c.write(" ");
writeln; // Tersten ilk 10 veri istendi...

//harf.rewind(); // Bu olmazsa sonraki döngü baştan başlamaz!

foreach(c; harf) c.write(" ");
writeln; // Bellekteki tüm veri istendi...
} /* Çıktısı:
Z Y X W V U T S R Q
P O N M L K J I H G F E D C B A
*/


İşte böyle...:)

Güzel şeyler bunlar, Zafer dahil katılım sağlarsa çok sevinirim...

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]
August 01, 2012

Ali hocam anlayamıyorum...:)

Doğru gitmeyen bir şeyler var. Bunu aynı yapı üzerinden işlemeye devam edelim mi?

Alıntı (acehreli):

>
> struct SayıDizisi
> {
>     int baş;
>     int son;
>
>     this(int baş, int son)
>     {
>         this.baş = baş;
>         this.son = son;
>     }
>
>     int opApply(int delegate(int sayı) işlem) const
>     {
>         /*
>          * Üzerinde konuşurken dışarıdaki foreach ile karışmasın diye bunu for
>          * ile gerçekleştirmeye karar verdim. Burada foreach de olabilirdi:
>          *
>          *   foreach (sayı; baş .. son) {
>          *       işlem(sayı);
>          *   }
>          */
>         for (int sayı = baş; sayı != son; ++sayı) {
>             immutable break_mi = işlem(sayı);
>
>             if (break_mi) {
>                 return break_mi;
>             }
>         }
>         return 0;
>     }
> }
> ```

Önce bu yapının döndürdüğü aralığı biraz genişlettim. Ayrıca derleyicinin 'foreach()' döngüsünü dönüştürdüğü benzeriyle birlikte çalıştırdım. Ayrıca kesme (immutable) isminde bir sabit değişken tanımladım...

Evet, (sayı%2) koşul ifadesi gerçekten de 2'ye ulaştığında yapı döngüsünde **'return'**'e sebep oluyor. Ama bu ifadesinin anlamı 2'ye bölünebilen ilk sayı da 0 döndür demek değil mi? O yüzden kesme değişkenine ne yazarsam yazayım, 0 hariç 1 sayısını kalansız bölemediği anda (ikinci dönüşte) **'break'** yapıyor. Bu baş etmemiz gereken ilk sorun ki çözümü kolay: (sayı%2 == 0)

import std.stdio;

void main(){
auto dizi = SayıDizisi(0, 30);
immutable kesme = 10;

foreach(sayı; dizi) {
sayı.write(" ");
if(sayı % kesme) break;
} // Aşağıdaki ile aynı...

writeln;

dizi.opApply(
(int sayı) {
sayı.write(" ");
if(sayı >= kesme) return 1;
return 0;
}
);
writeln;
}


opApply uygulamasının benzerinde ise (sayı >= kesme) ifadesi sanki istediğimiz gibi çalışıyor. Çünkü bu kodun çıktısı aşağıdaki çıktı oluyor. Ancak dikkat! Biz burada **'return'** kullandık ve hala **'break'** olup olmadığını tespit edebildiğimizi zannetmiyorum...:(

**Çıktısı:**
'0 1
0 1 2 3 4 5 6 7 8 9 10 '

Karışık veya henüz hakim olamadığım bir alan! O yüzden Ali hocamın parmaklarına bakıyorum şu an...:)

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]
August 01, 2012

Tamam, sorun kalmadı çünkü yukarıda verdiğim cevaba rağmen sorunu görememişim!

Biz 0'a takılmaktayız ve koşul ifadesi (sayı % kesme == 0) şeklinde olacak. Ben de 'break''i yakalayamadığımız yönünde şiddetli bir azap çekmek üzereydim...:)

   auto dizi = SayıDizisi(1, 30);
   immutable kesme = 10;

   foreach(sayı; dizi) {
       sayı.write(" ");
       if(sayı % kesme == 0) break;
   }

Yukarıdaki kodlar çalışıyor çünkü aralığı 1-30 arasında kurdum. O yüzden 10'a bölümde kesme (kırılma) olmakta.

Teşekkürler, faydalı bir muhabbet oldu...

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 01, 2012

Alıntı (acehreli):

>

Talihsiz bir isim olmuş ama sonundaki "me" olumsuzluk anlamında değil herhalde. Benim koşulumu neden beğenmedin?
...
Senin kafanı karıştırmış olmalıyım. Aslında çok basit: programcı tek sayı olunca döngüyü kırmak istiyor.

Hayır beğenmemekten çok, farklı bir çıktı alamadığımı ve doğru çalışmadığını fark ettim. Meğerse 2'ye kalansız bölünebilen bir sayıda break yapmak istemişsin. Ben ise daha çok anlayabilmek için bu sihirli sayıyı değiştirip 3, 4, 5 yapmak istedim ve farklı bir sonla karşılaşmadım. Ama aralığı 0'dan değil de 1'den başlatınca ve ifadeyi değiştirince farklı aralıklarda break yapılabildiğini hemen sonraki iletide (herhalde bu ikinci iletimi görmedin?) gösterdim. Sanki bu haliye daha güzel, en azından benim için...:)

Beğenmediğin kesme sabiti ise o an aklıma gelen, xSay, kSay, ySay da olabilecek herhangi bir şey olabilir. Çünkü her iki opApply uygulamasındaki ifadeleri değiştirmem gerekiyordu. Yoksa opApply içinde görünüp görünmemesi ile ilgilenmiyorum. O bana özel bir kolaylıktı, belki de paylaşmamalıydım...:)

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 01, 2012

Alıntı (acehreli):

>

Alıntı (acehreli):

>

dizi.opApply() açılımın yaparken opApply()'a gönderilen temsilcinin kullanıcının ortamına erişemediğini söylemek aklıma bile gelmemiş.

O söylediğim yanlış. Tabii ki kullanıcının temsilcisi kullanıcının ortamına erişebilir.
Sanırım bu çok önemli değil çünkü biz daha çok 'foreach()' döngüsü kolaylığı ile ilgileniyoruz. Sonuçta bu bir kolaylık ve basit bir şekilde (empty, popFront, front işlevlerini tanımlamadan) kullanabilmek çok güzel. Ancak önceki iletilerimde de ifade etmek istediğim gibi farklı çıktılar (öğrenciye değerleri değiştirme imkanı tanımak) gerekiyor. Örneğin artık şu şekilde istediğimiz yerde 'break' yaptırabiliyoruz; güzel değil mi?

import std.stdio;

void main(){
   auto dizi = SayıDizisi(1, 31);
   string döngü = "bitti"; // Eğer bu değişken değişmezse sorun var!

   foreach (sayı; dizi) {
       if(sayı % 13 == 0) {
           döngü = "kesildi";
           break;
       }
       sayı.write(" ");
   }
   writefln("\n\t-%s-", döngü);
}/* Çıktısı:
1 2 3 4 5 6 7 8 9 10 11 12
	-kesildi-
*/

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 01, 2012

Alıntı (Salih Dinçer):

>

bahsedilen break anı hangi döngü tarafından yapılıyor?

Eğer dışarıdaki foreach döngüsü bir 'break' ile kırılmışsa islemler() sıfırdan farklı bir değer döndürür. O değere bakmalıyız ve sıfırdan farklı olduğu zaman opApply() içindeki döngüyü de kırmalıyız.

Daha kolay görülsün diye daha da küçük bir yapı tanımladım. main()'deki kullanıcı kodları foreach'i erkenden kırmak istiyor (görülen ilk tek sayıda 'break' ile çıkıyor):

import std.stdio;

void main()
{
   auto dizi = SayıDizisi(0,5);

   foreach (sayı; dizi) {
       writeln(sayı);
       if (sayı % 2) {
           break;  // <--- Kullanıcı döngüyü ilk tek sayıda kırmak istiyor
       }
   }
}

struct SayıDizisi
{
   int baş;
   int son;

   this(int baş, int son)
   {
       this.baş = baş;
       this.son = son;
   }

   int opApply(int delegate(int sayı) işlem) const
   {
       /*
        * Üzerinde konuşurken dışarıdaki foreach ile karışmasın diye bunu for
        * ile gerçekleştirmeye karar verdim. Burada foreach de olabilirdi:
        *
        *   foreach (sayı; baş .. son) {
        *       işlem(sayı);
        *   }
        */
       for (int sayı = baş; sayı != son; ++sayı) {
           işlem(sayı);  // <--- Bu opApply'ın break'ten haberi yok
       }

       return 0;
   }
}

Çıktıdan anlaşıldığına göre döngü kırılmamış:

'0
1
2
3
4
'

Bunun nedeni, derleyicinin main()'deki döngüyü tam olarak şuna dönüştürmesidir:

   dizi.opApply(
       (int sayı) {
           writeln(sayı);
           if (sayı % 2) {
               return 1;  // "break ile çıkıldı" anlamında
           }

           return 0;  // "normal olarak sonlandı" anlamında
       }
   );

(O kodu main()'deki bütün foreach'in yerine yazabilirsiniz. Çıktı aynı olacak.)

Görüldüğü gibi, derleyici "kullanıcı break ile çıkmak istiyor" bilgisini, temsilciden sıfırdan farklı bir değer döndürerek veriyor. İşte opApply() içindeki döngüdeyken o değere bakmamız gerekir. Asıl kodu şöyle değiştiriyorum:

   int opApply(int delegate(int sayı) işlem) const
   {
       for (int sayı = baş; sayı != son; ++sayı) {
           immutable break_mi = işlem(sayı);

           if (break_mi) {
               return break_mi;
           }
       }

       return 0;
   }

(Not: break_mi'nin türü aslında int olsa da bir bool değişken gibi adlandırdım. dönüşDeğeri vs. de olabilirdi.)

Artık döngü ilk tek sayıda kırılır:

'0
1
'

Alıntı:

>

rewind() işlevinin neden lazım olabileceğini gösteriyor.

İşte o daha önce konuştuğumuz topluluk-aralık karşılaştırmasına bağlı. Aralık işlevleri doğrudan topluluk üzerinde olursa topluluktan istemeden eleman çıkartılır. Basit bir writeln() çağrısı bile topluluğu boşaltabiliyor.

O yüzden her topluluk elemanları üzerinde ilerlemeyi sağlayan bir aralık türü sunmalı ve ilerlendikçe bu aralık daralmalı; asıl topluluk korunmalı.

Bunu dilimlerde görüyoruz; popFront() ile dilim eleman kaybeder ama eriştirdiği elemanlar kendi dizilerinde durmaya devam ederler.

Ek olarak, eğer aralığın kendisi daha sonradan kullanılabilmek üzere saklanabiliyorsa o zaman save() işlevini sunar. save() elemanları kopyalamaz, aralığın durumunu saklar.

Bütün bunlara rağmen ben daha önceki bir gözlemime döneceğim: Yığın veri yapısı üzerinde eleman kaybetmeden ilerlemek zaten doğal gelmiyor çünkü ilerleme kavramı bütünüyle baştaki elemanı çıkartma kavramı üzerine kurulu. Ama yukarıda da gösterildiği gibi, bu yapının nasıl gerçekleştirildiğini (dilim kullanıyor) bilen bir yan aralık tanımlanabilir ve o aralık bütün elemanlar üzerinde ilerleyebilir. Ne olursa olsun bu bana doğal gelmiyor.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

August 01, 2012

Alıntı (Salih Dinçer):

>

Önce bu yapının döndürdüğü aralığı biraz genişlettim. Ayrıca derleyicinin 'foreach()' döngüsünü dönüştürdüğü benzeriyle birlikte çalıştırdım. Ayrıca kesme (immutable) isminde bir sabit değişken tanımladım...

Talihsiz bir isim olmuş ama sonundaki "me" olumsuzluk anlamında değil herhalde. Benim koşulumu neden beğenmedin? Bir sayının tek olup olmadığını anlamak için % işleci kullanılır ya... Bizim türümüzden bir nesneyi kendi foreach döngüsünde kullanmak isteyen programcı "tek sayı olduğunda yeter" demek istiyor. Şu değil midir:

       if (sayı % 2) {
           break;
       }

İstersek daha açık olarak ((sayı % 2) != 0) da yazabilirdik ama tabii ki '== 0' ters olurdu.

Senin kafanı karıştırmış olmalıyım. Aslında çok basit: programcı tek sayı olunca döngüyü kırmak istiyor.

Alıntı:

>

Evet, (sayı%2) koşul ifadesi gerçekten de 2'ye ulaştığında yapı döngüsünde 'return''e sebep oluyor. Ama bu ifadesinin anlamı 2'ye bölünebilen ilk sayı da 0 döndür demek değil mi?

Kullanıcının if ifadesine yazdığı koşulun işlem()'in döndürdüğü değerle ilgisi yok. Kural şu:

  • foreach'in içinde break'e rastlanmışsa işlem() sıfırdan farklı değer döndürür.

  • Değilse sıfır döndürür.

Alıntı:

>
>     dizi.opApply(
>         (int sayı) {
>             sayı.write(" ");
>             if(sayı >= kesme) return 1;
>             return 0;
>         }
>     );
> }
> ```


dizi.opApply() açılımın yaparken opApply()'a gönderilen temsilcinin kullanıcının ortamına erişemediğini söylemek aklıma bile gelmemiş. 'kesme' gibi yerel bir değişken orada görülemez.

Benim (ve derleyicinin) yaptığım çok daha basit bir şeydi: Dikkat edersen 'break' yerine 'return 1;' yazdım. if ile bir ilgisi yok. 'break' yerine körlemesine 'return 1' geldiğini düşün.

Alıntı:
> Karışık veya henüz hakim olamadığım bir alan!

Olay gerçekten çok basit: opApply() tanımladın ve içeride kendi döngün içinde ilerliyorsun. Kullanıcının 'break' isteğini nasıl sağlayacaksın? Çözüm: işlem()'in dönüş değeri sıfırdan farklıysa kullanıcı 'break' istemiş demektir. Hemen döngüden çıkıyoruz.

Ali

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]
August 01, 2012

Alıntı (acehreli):

>

dizi.opApply() açılımın yaparken opApply()'a gönderilen temsilcinin kullanıcının ortamına erişemediğini söylemek aklıma bile gelmemiş.

O söylediğim yanlış. Tabii ki kullanıcının temsilcisi kullanıcının ortamına erişebilir.

Alıntı:

>

'kesme' gibi yerel bir değişken orada görülemez.

'kesme' kendisi opApply() içindeyken görülemez ve görülmüyor da zaten. Temsilci içinden ise görülebilir ("ona erişilebilir" anlamında).

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]