Thread overview
Aralıkları Anlamak
May 08, 2013
Salih Dinçer
May 08, 2013
Salih Dinçer
May 08, 2013

Merhaba,

Uzun uzadıya değinilebilir! Sanırım kısa kısa örnekler ile devam edersek daha çok şey anlayacağız...:)

Aralıkları ilk gördüğümde bana garip geliyorlardı ve pek anlamıyordum. Bunun sebebi, aralıkları(range) ilk olarak D'de tanımam olabilir. Bilmiyorum, başka dillerde kullanılmaya başlandı mı?

Belki fikir sahibi olmak için, ilk önce D.ershane'deki şu başlığı okumalısız:

http://ddili.org/ders/d/araliklar.html

Şimdi anladığımı yazacağım, bu örnek ile doğrulamaya çalışacağım. Ancak bu örnekler belden aşağı olacak! Yani farklı örnekler olacak. Maksat uçlarda gezip işin doğasını, sınırını gözlemlemek. Güncel olduğu için aklıma ilk gelen örnek:

   struct Foo
   {
     int i;

     bool empty() {
       return i == 16;
     }

     int front() {
       return i;
     }

     void popFront() {
       i++;
     }
   }

   import std.stdio;

void main() {

 Foo foo;
 foreach(f; foo)
 {

   f.write("-", foo.front, " ");

 }
 writeln;
}

Yukarıda basit bir aralık örneği görüyoruz. Sayaç vazifesi gören i değişkeni ile 3 tane özelleştirilmiş işlevlerimiz var. Yaptıkları gerçekten çok basit öyle değil mi? Sayalım, i'nin:

  • 16'ya eşit olup olmadığını sorguluyor
  • içerdiği değeri gönderiyor
  • değerini bir arttırıyor

Sonuçta 0'dan 15'e kadar ekrana sayıları yazıyoruz. Çünü empty()'den true onayı gelmediği müddetçe döngü dönmeye ve front()'dan aldığı veriyi ekrana yazmaya devam ediyor. Yani bütün olay yukarıda maddelediğim sırada devam ediyor...

Peki f değişkeni döngü tarafından alınan front()'un bir kopyası ise aynı anda front()'u yazdırdığımızda ne olmasını beklersiniz? Aşağıdaki gibi bir sonuç olabilir mi?

Alıntı:

>

'0-0 1-0 2-0 3-0 4-0 5-0 6-0 7-0 8-0 9-0 10-0 11-0 12-0 13-0 14-0 15-0 '

Evet, sonuç gerçekten böyle çıkıyor. Yani her zaman aralığın en başındaki elemanı veriyor. Bu bana garip geliyor ve niye olduğunu anlamaya çalışıyorum. Belki de henüz aralıkları tam olarak anlayabilmiş değilimdir...:)

Başarılar...

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

May 08, 2013

Alıntı (acehreli):

>

Alıntı:

>
> >   Foo foo;
> >   foreach(f; foo)
> > ```

>
> foreach'in içinde tüketilen Foo, foo'nun bir kopyası. popFront() hep o kopya üzerinde çağrıldığı için foo.front() hep 0 döndürüyor.
>
Bunu bilmiyordum, gerçekten ilginç ve bir de şu şekilde denediğimde kopyasını çıkaramadığı için beklediğim sonucu aldım...

auto foo = new Foo();
foreach(f; foo) {
: : :


Bunu öğrendiğim iyi oldu. Zaten yapılar ve sınıflar arasındaki kopya çıkarma olayını biliyorduk. Bunu aralıklar ile perçilendiğimiz harika oldu.

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

Alıntı (Salih Dinçer):

>

Bilmiyorum, başka dillerde kullanılmaya başlandı mı?

Aslında Boost kütüphanelerinde de çok benzer yapılar varmış. Boost kütüphanelerini kullanan C++ projeleri de yararlanabilirler ama C++'ın kendi standart kütüphanesinde aralık yok.

Alıntı:

>
>   Foo foo;
>   foreach(f; foo)
> ```


foreach'in içinde tüketilen Foo, foo'nun bir kopyası. popFront() hep o kopya üzerinde çağrıldığı için foo.front() hep 0 döndürüyor.

Bu konu D forumlarında da açılmıştı. Andrei'nin yanıtı da "sırf elemanlarını yazdırdığımız için aralık tükenmesin diye" demişti. Özetle, foo foreach'ten sonra bile kullanılmamış durumda.

(Böylece, benim diğer konuda front()'un çağrılmasıyla ilgili olarak altını çizdiğim sakınca aslında foreach aralığını değil, yerel aralığı etkiler.)

Alıntı:
> aralıkları tam olarak anlayabilmiş

Aralıkların gariplikleri oluyor. Örneğin, File.byLine()'ın döndürdüğü string'in de .dup ile kopyalanması gerekir çünkü okunan her satır perde arkasında aynı string'e yazılır.

Ali

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

Merhaba,

Zombi olmuş bir başlığı tekrar hortlattığım için kusura bakmayın. Bütün çabam InputRange işlevlerini (_r.back; _r.front; _r.empty; _r.popBack():void; _r.popFront():void;) daha iyi anlamak ve anlatmak. Bunun için bugün Çift Yönlü ve Erişimli Aralık döndüren bir yığıt yaptım. Bunu zaten geçmişte TriBit başlığı ile gerçeklemiştim. Tabi orada özel bir bool veri türü kullanıyordum: https://forum.dlang.org/post/1030.8280@ddili.org

Aşağıdaki kodun türü, foreach_reverse()'ü kullanarak FIFO mantığı ile çalışan bir yığıt. Aynı şekilde true parametresi gönderilmezse geleneksel LIFO (Son Giren İlk Çıkar) işletiliyor. Çıktısı, sırasıyla 2 kere ACGT ve tersi 2 kere TGCA yazmak :)

Tabi çıktının yarısında while(!empty) kullanılmasını ve InputRange ile mükemmel uyumlu olmasını dikkatinize sunarım! En önemli fark, foreach() aralığı tüketmezken diğer öyle değil!

/* DNAstack.d by dbey
 * 02.07.2021
 *
 * https://github.com/dlang/phobos/pull/4010
 *
 */
import std.stdio;

enum DNA { A,  // [ 0, 0 ]
           C,  // [ 0, 1 ]
           G,  // [ 1, 0 ]
           T   // [ 1, 1 ]
         }/****** [ L, R ] ******/

struct DNAstack {
  bool FIFO;
  bool[] data;
  size_t index;

  void init (DNA[] customData = [], bool stackType = false )
  {
    FIFO = stackType;
    foreach (dna; customData)
    {
      data ~= this.decode (dna);
    }
    if (FIFO)
    {
      index = 0;
    } else {
        index = data.length/2;
    }
  }

  private bool[] decode (DNA n)
  {
    bool left, right;
    if(n == DNA.G || n == DNA.T) left = true;
    if(n == DNA.C || n == DNA.T) right = true;

    return [ left, right];
  }

  private DNA encode (bool[] code)
  {
    int result;
    if (code[0]) result += 2;
    if (code[1]) result += 1;

    return cast(DNA)result;
  }

  void push (DNA veri) @property
  {
    if(!FIFO) index += 2;
    data ~= this.decode(veri);
  }

  DNA pop () @property
  {
    bool left, right;
    if(FIFO)
    {
      index += 2;
      left = data[index-2];
      right = data[index-1];
    } else {
      index -= 2;
      left = data[index];
      right = data[index+1];
    }
    return encode([ left, right]);
  }

  void popBack () @property
  {
    index += 2;
  }

  DNA back () @property
  {
    auto left = data[index];
    auto right = data[index+1];
    return encode([ left, right]);
  }

  void popFront () @property
  {
    index -= 2;
  }

  DNA front () @property
  {
    auto left = data[index-2];
    auto right = data[index-1];
    return encode([ left, right]);
  }

  bool empty () @property
  {
    if(FIFO) {
      return index == data.length ;
    } else {
      return index == 0;
    }
  }
}

void main()
{
  DNAstack s;
  with(DNA)
  {
    s.init(     [A, C, G, T], true     );

    foreach_reverse(n; s) n.write;
    writeln(": ", s.index);

    while(!s.empty) s.pop.write;
    writeln(": ", s.index);

    s.init(     [A, C, G, T]           );

    foreach(n; s) n.write;
    writeln(": ", s.index);

    while(!s.empty) s.pop.write;
    writeln(": ", s.index);
  }
} /* ÇIKTISI:
rdmd DNAstack.d

ACGT: 0
ACGT: 8
TGCA: 8
TGCA: 0

https://tour.dlang.org/ */

Başarılar...

July 02
[Yanlışlıkla Salih'e göndermişim. Bir kere de buraya...]

On 7/2/21 10:04 AM, Salih Dincer wrote:

> Zombi olmuş bir başlığı tekrar hortlattığım için kusura bakmayın.

Eski konuyla tam ilgili değilse yeni konu açmak her açıdan daha iyi oluyor.

> Bütün
> çabam InputRange işlevlerini (_r.back;  _r.front; _r.empty;
> _r.popBack():void; _r.popFront():void;) daha iyi anlamak ve anlatmak.

BidirectionalRange demek istemişsin; çünkü InputRange işlevleri empty, front, ve popFront'tur.

> Bunun için bugün Çift Yönlü ve Erişimli Aralık döndüren bir yığıt
> yaptım.

Evet, yığıt bir aralık döndürseydi çok daha kullanışlı olurdu. 'index'i topluluğun parçası yapmak, aynı aralık üzerinde bir seferde tek bir ilerleme işlemi yapılabildiğini gösterir.

Ayrıca, bu yığıt en temel aralık ilkesini gözardı ediyor: aralık, topluluk değildir; ona erişim sağlar. Örneğin, aralığın popFront'unu çağırmak topluluğu etkilememelidir. Bunu, D'nin dizileriyle şöyle açıklayabiliriz: Dilim (slice) aralıktır, istediğimiz kadar tüketebiliriz ama dizide (array) değişiklik olmaz.

Tabii burada sen de haklısın: D'nin dizileriyle dilimleri kavramsal olarak çok iç içe olduklarından yukarıda söylediğimin önemi gözden kaçabiliyor. Olsun... Dinamik bir dizi, D runtime'a (veya "çöp toplayıcı"ya) ait olan isimsiz bir topluluktur. O topluluğa dilimle erişilir. D'deki karışıklık, dizinin ismi olmadığından dilimi dizi gibi düşünüyor oluşumuz...

> true parametresi gönderilmezse
> geleneksel LIFO (Son Giren İlk Çıkar) işletiliyor.

O gibi düzen parametrelerini artık hiç 'bool' olarak kullanmıyoruz çünkü örneğin bir 'true'nun ne anlama geldiği kullanıldığı noktada bilinemiyor. Onun yerine Flag!"erişim" gibi bir tür veya bir enum kullanmak daha açıklayıcı oluyor:

enum Tür { lifo, fifo }

> struct DNAstack {
>    bool FIFO;
>    bool[] data;

Veriyi öyle bool dizisi olarak tutmayı yer kazanmak için mi düşündün? Öyleyse tam tersi olmuş çünkü DNA değerleri tek baytta tutulabilecekken iki bool olarak şimdi iki baytta tutuluyorlar. Üstelik her seferinde DNA ve bool arasında dönüşüm gerekiyor.

Burada belki BitArray kullanılabilirmiş ama ben olsam gerçekten gerekmediği sürece basitçe ubyte[] kullanırdım:

  https://dlang.org/phobos/std_bitmanip.html#BitArray

>          index = data.length/2;

Sanki o işlemle daha sonraki 'index += 2' işlemleri çelişiyor.

>    void push (DNA veri) @property

@property kullanımı artık önerilmiyor ve zaten push() ve pop() gibi işlevlerle pek uyumlu değil. 'Property', bir üye değişkenmiş gibi kullanılan ama aslında işlevlerle gerçekleştirilen bir kavram. İşte, @property'yi kullanmadan türe 'i' "property"si ekleyen bir kod:

struct S {
  int i_;

  int i() {
    return i_;
  }

  void i(int yeni) {
    i_ = yeni;
  }
}

void main() {
  auto s = S();
  s.i = 42;          // <-- int alan işlevi çağırır
  assert(s.i == 42);
}

Sonuçta benim önerim, şurada anlatıldığı gibi opSlice tarafından döndürülen bir Aralık türü tanımlamak:

  http://ddili.org/ders/d/islec_yukleme.html#ix_islec_yukleme.opSlice

Ama o bölüm kitapta aralıklardan önce geçtiğinden Aralık türünün InputRange işlevleri yok; onlar da eklenebilir. :)

Ali


July 04

On Friday, 2 July 2021 at 21:54:10 UTC, Ali Çehreli wrote:

>

[Yanlışlıkla Salih'e göndermişim. Bir kere de buraya...]

Dlang Community içinde bir DM sistemi mi var?

>

Eski konuyla tam ilgili değilse yeni konu açmak her açıdan daha iyi oluyor.

Açtım: https://forum.dlang.org/post/zsxlwlqwbkwkysdbzckw@forum.dlang.org

ve...

Bu sefer Rosalind Project ile ilişkilendirdim. Çünkü şaşırtıcı şekilde, sadece bir invertData()'a sayesinde ilgili soruyu çözebilme yeteneği olduğunu fark ettim. Eminim, sitedeki diğer birçok soru bu şekilde çözülebilir! Boş bir vakitte XP almak için deneyeceğim...

>

BidirectionalRange demek istemişsin; çünkü InputRange işlevleri empty, front, ve popFront'tur.

Maalesef yabancı dildeki bu terimleri karıştırıyorum. Benim için front neyse back de aynı kefede. Sadece foreach'in diğer türüyle de uyumlu şekilde kullanabildiğimi görmek beni heyecanlandırıyor. Ekstra olanaklar olsa iyi olur mu diye o tartışmaya girmiyorum; zaten şurada yeterince tartışılmış ve evet, Andrei'ye hak veriyorum:

https://github.com/dlang/phobos/pull/4010
(Kapanmış ve başka hata ile ilişkilendirilmiş konu!

>

Ayrıca, bu yığıt en temel aralık ilkesini gözardı ediyor: aralık, topluluk değildir; ona erişim sağlar. Örneğin, aralığın popFront'unu çağırmak topluluğu etkilememelidir. Bunu, D'nin dizileriyle şöyle açıklayabiliriz: Dilim (slice) aralıktır, istediğimiz kadar tüketebiliriz ama dizide (array) değişiklik olmaz.

Aslında foreach(), bu BidirectionalRange'i kullanırken yapının bir kopyasını alması ve topluluğun üyelerini kullanıp orijinaline dokunmaması benim için yeterli. Dilim kullanmak konusuna gelince: Evet, daha sık kullanmalıyım...

> >

true parametresi gönderilmezse
geleneksel LIFO (Son Giren İlk Çıkar) işletiliyor.

O gibi düzen parametrelerini artık hiç 'bool' olarak kullanmıyoruz çünkü örneğin bir 'true'nun ne anlama geldiği kullanıldığı noktada bilinemiyor. Onun yerine Flag!"erişim" gibi bir tür veya bir enum kullanmak daha açıklayıcı oluyor:

enum Tür { lifo, fifo }

Kesinlikle haklısın hocam! Bu konuda FIFO_is() @property'si ile sayenizde yeni bir yaklaşım ürettim. Çünkü benim için daha anlaşılır: FIFO, true değilse o koşula girilmez veya false olarak işaretliyse LIFO olarak çalışacaktır:

      public void FIFO_is (bool FIFO) @property {
        this.FIFO = FIFO;
        if (FIFO) this.index = 0;
      }

Nasıl çözüm?

> >

struct DNAstack {
bool FIFO;
bool[] data;

Veriyi öyle bool dizisi olarak tutmayı yer kazanmak için mi düşündün?

Kesinlikle hayır! Çünkü odak noktamda anlaşılma kolaylığı ve etkili öğrenme hızı var. Ama bir gün, BitArray ile benzer yüklemeleri (opOpAssign) icra edersem birebir hız karşılaştırması yapmak istiyorum; özellikle kendi geliştirdiğim BitDerle sınıfı ile...

>

Burada belki BitArray kullanılabilirmiş ama ben olsam gerçekten gerekmediği sürece basitçe ubyte[] kullanırdım:

Evet, hatırlatınca denedim. Sadece 3 satırı (biri tanımlandığı yapının başı) değiştirerek kolayca kullanılabildiğini gördüm. Özellikle gerçek DNA transkriptleri (büyük yapılarda GB'larca veri) ile bir deneme yapmak zorlayıcı bir örnek olabilir.

Örneğin, sevgili Damla'nın ilgisini çekebilecek Mitokondriyal DNA (mtDNA)'dan kısa bir dizi (1859 byte):

ACADS (NM_000017.4): https://www.ncbi.nlm.nih.gov/nuccore/1518494109/

Şimdiki gelişen nesil, programlama dillerini kullanarak bu veriler üzerinde çalışma yapıyorlar. Sanırım daha çok Python kullanılıyor ama D'yi düşünsünler derim!

>

https://dlang.org/phobos/std_bitmanip.html#BitArray

>
     index = data.length/2;

Sanki o işlemle daha sonraki 'index += 2' işlemleri çelişiyor.

O nereden geldi! Sanırım hızlıca kod geliştirmekten kaynaklı. Tekrar düzenlediğimde 2 katını aldığımı fark ettim. Demek ki kafamda bir şeyler karışmış olacak :)

S.Dinçer

July 04
On 7/4/21 12:32 PM, Salih Dincer wrote:

> On Friday, 2 July 2021 at 21:54:10 UTC, Ali Çehreli wrote:
>> [Yanlışlıkla Salih'e göndermişim. Bir kere de buraya...]
>
> Dlang Community içinde bir DM sistemi mi var?

Ben Thunderbird kullanıyorum. Zamanında kurulmuş olan bir eklenti de ayrı bir "Reply" düğmesi getiriyor ama farklı çalışıyor: Gruba göndermek yerine gönderene gönderiyor. Dikkat etmeyince böyle aksaklıklar olabiliyor.

On 7/4/21 12:32 PM, Salih Dincer wrote:

>> BidirectionalRange demek istemişsin; çünkü InputRange işlevleri empty,
>> front, ve popFront'tur.
>
> Maalesef yabancı dildeki bu terimleri karıştırıyorum. Benim için front
> neyse back de aynı kefede.

Öyle tabii ama her topluluk destekleyemiyor. Örneğin, girişten gelen satırlar için back() verebilmek için bütün satırları saklamak ve girişin sonuna kadar beklemek gerekir.

Şu ilkeleri hatırlıyorum:

- Algoritma, topluluktan olabildiğince az yenetek beklemeli. Örneğin, InputRange ile işleyebiliyorsa onunla yetinmeli.

- Topluluk, olabildiğince çok yetenek sunmalı. Örneğin, kendisine RandomAccessRange olarak erişim sunabiliyorsa opIndex() vs. işlevlerini tanımlamalı.

Topluluklar ve algoritmalar o zaman en kullanışlı olurlar.

> ```d
>        public void FIFO_is (bool FIFO) @property {
>          this.FIFO = FIFO;
>          if (FIFO) this.index = 0;
>        }
> ```
> Nasıl çözüm?

İşlevin isminde FIFO olması durumu iyi kurtarıyor. :)

Ancak, @property sözcüğünü unut. O sözcüğün kullanımı artık önerilmiyor çünkü hem burada bir etkisi yok (sildiğinde programında en ufak bir değişiklik olmayacak) hem de kullanımının getirdiği tek etki, benim şimdi hatırlayamadığım kadar ucubik.

>> > struct DNAstack {
>> >    bool FIFO;
>> >    bool[] data;
>>
>> Veriyi öyle bool dizisi olarak tutmayı yer kazanmak için mi düşündün?
>
> Kesinlikle hayır! Çünkü odak noktamda anlaşılma kolaylığı ve etkili
> öğrenme hızı var.

Ben yine de en hızlısının bir ubyte[] veya int[] olduğunu düşünüyorum çünkü hiç dönüşüm gerekmiyor. :) Örneğin, aşağıdaki tanımın değerleri ubyte'tır.

  enum DNA : ubyte { A, C, G, T }

> Sadece 3 satırı (biri tanımlandığı yapının
> başı) değiştirerek kolayca kullanılabildiğini gördüm.

D'nin en sevdiğim taraflarından birisi, tasarımı değiştirince çoğu zaman kodda çok az değişiklik gerekmesi.

> Sanırım daha çok Python kullanılıyor ama
> D'yi düşünsünler derim!

Mevcut araçlar Python olunca herkes doğal olarak o tarafa kayıyor.

Ali