Ders 11 / 27
Yineleme Yapıları
Aynı on kaynak üç kayıt biçiminde yazılır: elle on blok, sayı temelli yineleme, küme temelli yineleme. Satır sayısı, istisnanın maliyeti ve adres kararlılığı sayılır; ortadan bir bölge çıkarıldığında sayı temelli biçimin altı kalemlik plan ürettiği, kayan beş adresin ölçüm ağında otuz beş kaçan sayaç partisine karşılık geldiği ölçülür.
İçindekiler
Bir önceki dersin kaydında iki toplayıcı makine vardı ve ikisi ayrı ayrı, dört satırı harfi harfine aynı olan iki blok olarak yazılmıştı. Bölge büyüdü: ölçüm ağı artık on ayrı alt bölgede sayaç okuyor. Aynı bloğu on kez kopyalamak bir seçenek, kaydın kendisine “bunu on kez yap” demek başka bir seçenek. Bu ders üçüncü bir seçeneği de ekler ve üçünü aynı kalemlerde karşılaştırır.
Karşılaştırmanın çıkış noktası şudur: üç biçim de aynı gerçeği üretir. On makine, aynı alt ağlar, aynı boyutlar, aynı etiketler. Aralarındaki fark gerçekte değil, kayıtta ve kaydın kaynağa verdiği adrestedir. O adres, kaydın bir sonraki uygulamada hangi gerçek kaynağı kastettiğini belirleyen tek şeydir — ve bu dersin bütün sayıları oradan çıkar.
Ölçüm bölgesel ölçüm ağı üzerindedir ve kurgudur; koşan şey node ile kurulmuş bir
modeldir.
BS31. Ölçüm ağı on alt bölgede sayaç okur; bölge adları listede yazılı sıradadır.
BS32. Üç kayıt biçimi de aynı on makineyi tanımlar; nitelikleri birebir aynıdır.
BS33. Adres, kaynağın durumda bulunduğu anahtardır: elle biçimde blok adı, sayı temelli
biçimde sıra numarası, küme temelli biçimde harita anahtarı.
BS34. Bir bölge iki kat sayaç taşır ve makinesi büyük olmalıdır; bu, biçimlerin istisnayı nasıl
taşıdığını ölçmek için konmuş tek sapmadır.
BS35. altag ve etiket alanları yerinde güncellenemez; değişirlerse kaynak yeniden
oluşturulur. boyut yerinde güncellenir.
BS36. Her toplayıcı 15 saniyede bir sayaç partisi çeker. Yeniden oluşturulan bir makine, önceki
dersin süreleriyle 105 saniye hizmet dışıdır.
Aynı On Kaynak, Üç Kayıt
// yineleme.mjs — on kaynak uc bicimde yazilir; satir, adres kararliligi ve plan sayilir. Model. export const BOLGE = ["kuzey_1", "kuzey_2", "kuzey_3", "dogu_1", "dogu_2", "dogu_3", "bati_1", "bati_2", "bati_3", "bati_4"]; const ISTISNA = { dogu_2: "buyuk" }; // BS34: bir bolge iki kat sayac tasiyor const nitelik = (b, ist) => ({ altag: `altag.${b}`, boyut: ist[b] ?? "orta", etiket: `toplayici-${b}` }); export function elle(bolgeler, ist = ISTISNA) { const metin = bolgeler.map((b) => `kaynak makine "toplayici_${b}" {\n` + ` altag = altag.${b}.kimlik\n boyut = "${ist[b] ?? "orta"}"\n` + ` etiket = "toplayici-${b}"\n}`).join("\n"); const cozum = new Map(bolgeler.map((b) => [`makine.toplayici_${b}`, nitelik(b, ist)])); return { metin, cozum, dal: 0 }; // deger kendi blogunda, kosul yok } export function sayiTemelli(bolgeler, ist = ISTISNA) { const dal = Object.entries(ist).map(([k, v]) => `bolgeler[sayi.indeks] == "${k}" ? "${v}" : `).join(""); const metin = `yerel bolgeler = [${bolgeler.map((b) => `"${b}"`).join(", ")}]\n` + `kaynak makine "toplayici" {\n sayi = ${bolgeler.length}\n` + ` altag = altag[bolgeler[sayi.indeks]].kimlik\n boyut = ${dal}"orta"\n` + ` etiket = "toplayici-" + bolgeler[sayi.indeks]\n}`; const cozum = new Map(bolgeler.map((b, i) => [`makine.toplayici[${i}]`, nitelik(b, ist)])); return { metin, cozum, dal: Object.keys(ist).length }; } export function kumeTemelli(bolgeler, ist = ISTISNA) { const metin = "yerel bolgeler = {\n" + bolgeler.map((b) => ` ${b} = "${ist[b] ?? "orta"}"`).join("\n") + "\n}\n" + `kaynak makine "toplayici" {\n kume = bolgeler\n` + " altag = altag[kume.anahtar].kimlik\n boyut = kume.deger\n" + ' etiket = "toplayici-" + kume.anahtar\n}'; const cozum = new Map(bolgeler.map((b) => [`makine.toplayici["${b}"]`, nitelik(b, ist)])); return { metin, cozum, dal: 0 }; // istisna haritanin degerinde } const YENIDEN = ["altag", "etiket"]; // BS35: bu alanlar yerinde guncellenemez export function planla(once, sonra) { const p = { ekle: 0, degistir: 0, yeniden: 0, sil: 0 }; for (const [adres, y] of sonra.cozum) { const e = once.cozum.get(adres); if (!e) { p.ekle++; continue; } const fark = Object.keys(y).filter((k) => e[k] !== y[k]); if (fark.length) fark.some((k) => YENIDEN.includes(k)) ? p.yeniden++ : p.degistir++; } for (const adres of once.cozum.keys()) if (!sonra.cozum.has(adres)) p.sil++; return p; } export const BICIM = [["elle on blok", elle], ["sayi temelli", sayiTemelli], ["kume temelli", kumeTemelli]]; const satir = (m) => m.split("\n").length; const UC = { dogu_2: "buyuk", bati_1: "buyuk", kuzey_3: "kucuk" }; if (import.meta.url === `file://${process.argv[1]}`) { // Uc bicim ayni on gercek kaynagi mi uretiyor: adresi degil, nitelikleri karsilastir. const imza = (c) => [...c.values()].map((v) => JSON.stringify(v)).sort().join("|"); const imzalar = BICIM.map(([, f]) => imza(f(BOLGE).cozum)); console.log("uc bicim de ayni gercegi uretiyor mu: " + `${imzalar.every((x) => x === imzalar[0]) ? "evet" : "hayir"} ` + `(${elle(BOLGE).cozum.size} kaynak, ayni nitelikler)`); console.log("\nkaydin bedeli (10 kaynak)"); console.log("bicim satir kosul dali 3 istisnada satir/dal adreste bolge adi"); for (const [ad, f] of BICIM) { const r = f(BOLGE), u = f(BOLGE, UC); const adresli = [...r.cozum.keys()].some((a) => a.includes("dogu_2")); console.log(`${ad.padEnd(15)}${String(satir(r.metin)).padStart(5)}${String(r.dal).padStart(12)}` + `${`${satir(u.metin)}/${u.dal}`.padStart(23)}${(adresli ? "var" : "yok").padStart(19)}`); } const SENARYO = [ ["ortadan bir bolge cikti (dogu_2 kapandi)", BOLGE.filter((b) => b !== "dogu_2")], ["ortaya bir bolge girdi (dogu_1b acildi)", [...BOLGE.slice(0, 4), "dogu_1b", ...BOLGE.slice(4)]], ["sona bir bolge eklendi (bati_5 acildi)", [...BOLGE, "bati_5"]], ]; for (const [ad, yeni] of SENARYO) { console.log(`\n${ad}`); console.log("bicim ekle degistir yeniden olustur sil toplam kalem kayan adres"); for (const [bAd, f] of BICIM) { const once = f(BOLGE), sonra = f(yeni), p = planla(once, sonra); const kayan = [...sonra.cozum].filter(([a, v]) => once.cozum.has(a) && JSON.stringify(once.cozum.get(a)) !== JSON.stringify(v)).length; console.log(`${bAd.padEnd(15)}${String(p.ekle).padStart(4)}${String(p.degistir).padStart(10)}` + `${String(p.yeniden).padStart(17)}${String(p.sil).padStart(5)}` + `${String(p.ekle + p.degistir + p.yeniden + p.sil).padStart(14)}${String(kayan).padStart(13)}`); } } }
uc bicim de ayni gercegi uretiyor mu: evet (10 kaynak, ayni nitelikler) kaydin bedeli (10 kaynak) bicim satir kosul dali 3 istisnada satir/dal adreste bolge adi elle on blok 50 0 50/0 var sayi temelli 7 1 7/3 yok kume temelli 18 0 18/0 var ortadan bir bolge cikti (dogu_2 kapandi) bicim ekle degistir yeniden olustur sil toplam kalem kayan adres elle on blok 0 0 0 1 1 0 sayi temelli 0 0 5 1 6 5 kume temelli 0 0 0 1 1 0 ortaya bir bolge girdi (dogu_1b acildi) bicim ekle degistir yeniden olustur sil toplam kalem kayan adres elle on blok 1 0 0 0 1 0 sayi temelli 1 0 6 0 7 6 kume temelli 1 0 0 0 1 0 sona bir bolge eklendi (bati_5 acildi) bicim ekle degistir yeniden olustur sil toplam kalem kayan adres elle on blok 1 0 0 0 1 0 sayi temelli 1 0 0 0 1 0 kume temelli 1 0 0 0 1 0
İlk satır karşılaştırmanın zeminidir: üç biçim de on kaynağı aynı niteliklerle üretiyor. Kayıt biçimi gerçeği değiştirmiyor.
Satır sütunu ilk bedeli verir. Elle yazım 50 satır, küme temelli 18, sayı temelli 7. Elle yazımın 50 satırının 40’ı tekrardır: aynı üç alan on kez, yalnız bölge adı değişerek. Sayı temelli biçim en kısasıdır çünkü listeyi tek satıra sıkıştırır. Küme temelli biçim aradadır ve fazlalığı rastlantı değildir — haritanın her satırı bir bölgeyi adıyla ve değeriyle yazar.
Koşul dalı sütunu istisnanın fiyatını verir. Bir bölgenin büyük makine istemesi, elle yazımda o bloğun kendi satırına yazılan bir değerdir; küme temelli biçimde haritanın o anahtarındaki değerdir; ikisinde de sıfır koşul. Sayı temelli biçimde ise ifadeye bir dal girer. Son sütundan bir öncekine bakıldığında bunun nasıl büyüdüğü görülür: istisna sayısı üçe çıkınca elle ve küme temelli biçimlerde satır ve dal sayısı değişmez, sayı temelli biçimde tek satırda üç iç içe koşul birikir. İstisnayı taşıyan yer, sayı temelli biçimde kaydın veri kısmı değil ifade kısmıdır.
Son sütun ise bu dersin asıl kalemidir. Elle ve küme temelli biçimlerde adres bölge adını taşır:
makine.toplayici_dogu_2 ya da makine.toplayici["dogu_2"]. Sayı temelli biçimde adres
makine.toplayici[4]tür ve dördüncü sıranın hangi bölge olduğu adreste yazmaz — o bilgi listenin
uygulama anındaki hâlindedir. Durumda bir kaynağa bakıp hangi bölgeye ait olduğunu söylemek
için kaydın o günkü sürümünü bulmak gerekir.
Adresin ne olduğu bir ayrıntı gibi görünür, ama bu kursun ölçüsünde merkezî bir kalemdir. Kayıt uygulandığında her kaynağın gerçek kimliği bir adresin altına yazılır; bir sonraki uygulamada kayıt ile gerçeği eşleştiren tek şey o adrestir. Adres kaynağın kimliğini taşıyorsa eşleşme kaydın kendisinden okunur; sıra numarası taşıyorsa eşleşme kaydın o günkü sırasına bağlıdır. İkinci durumda kayıt ile gerçek arasındaki bağ, kayıtta yazılı olmayan bir şeye — listenin geçmişteki hâline — dayanır.
Ortadan Bir Eleman Çıkınca
Üç senaryo aynı çıktının alt bölümlerindedir ve birlikte okunduğunda kural nettir.
dogu_2 bölgesi kapandığında elle ve küme temelli biçimler tek kalemlik plan üretir: bir kaynak
silinir, diğer dokuzu hiç dokunulmadan yerinde kalır. Sayı temelli biçim aynı gerçek değişiklik
için altı kalem üretir: beş yeniden oluşturma ve bir silme. Sebep aritmetiktir. Liste dördüncü
elemanını kaybedince beşinci eleman dördüncü sıraya, altıncı beşinciye kayar; makine.toplayici[4]
adresi dün dogu_2yi gösteriyordu, bugün dogu_3ü gösteriyor. Kayıt “dördüncü makinenin alt ağı
ve etiketi değişti” der; bu iki alan yerinde güncellenemediği için karar yeniden oluşturmadır.
Kayan adres sütunu bunu doğrudan sayar: beş adres artık başka bir gerçek kaynağa işaret ediyor.
Ortaya bir bölge girmesi daha da pahalıdır: yedi kalem, altı kayan adres. Ekleme noktasından sonraki her adres bir kayar.
Üçüncü senaryo sınırı çizer. Bölge listenin sonuna eklendiğinde üç biçim de tek kalem üretir; sayı temelli biçim de temizdir, çünkü hiçbir adres kaymaz. Yani sayı temelli yineleme yanlış değil, sırası anlam taşımayan ve yalnız sondan büyüyen kümeler için doğru biçimdir. Bölge listesi öyle bir küme değildir: bölgeler kapanır, araya yenisi girer.
Planın öngörme oranı burada tersine bir soru sorar. Plan yanılmıyor — sayı temelli biçimde “beş kaynak yeniden oluşturulacak” diyor ve uygulamada tam beşi yeniden oluşturuluyor, oran 5/5. Yanılan plan değil, planı okuyan kişinin beklentisidir: bir bölge kapandı, bir makine gitmeli. Beklenti bir kalem, plan altı kalem. Aradaki beş kalem gerçeklikten değil, kayıt biçiminden doğuyor.
Kaydın bunu kendi başına fark edememesi de ölçülebilir bir sınırdır. Kayıt “beşinci makinenin alt ağı değişti” ile “beşinci sıra artık başka bir bölge” arasındaki farkı göremez, çünkü elinde yalnız adres ve nitelikler vardır. İkisi de aynı şeye benzer: bir adres, değişmiş nitelikler. Ayrımı ancak kaydı yazan kişi bilir, ve o kişi de planı okurken beş kalemi gerçek bir değişiklik sanabilir. Sayı temelli biçimin riski gizli değildir — planda açıkça yazar — ama planın altı kalemi ile gerçeğin bir kalemi arasındaki farkı ayırt etmek okuyucuya bırakılmıştır.
Kayan Adresin Ölçüm Ağındaki Karşılığı
// bedel.mjs — plan kalemini olcum agi biriminde sayar: kacan sayac partisi. Model. import { BOLGE, BICIM, planla } from "./yineleme.mjs"; const DISI = 105, PERIYOT = 15, YENIDEN_SN = 110, SIL_SN = 10; // BS36, onceki dersin sureleri const yeni = BOLGE.filter((b) => b !== "dogu_2"); console.log("dogu_2 kapandi — ayni gercek degisiklik, uc kayit bicimi"); console.log("bicim yeniden hizmet disi makine-sn kacan parti uygulama sn"); for (const [ad, f] of BICIM) { const p = planla(f(BOLGE), f(yeni)); const sn = p.yeniden * DISI; console.log(`${ad.padEnd(15)}${String(p.yeniden).padStart(7)}${String(sn).padStart(22)}` + `${String(p.yeniden * Math.floor(DISI / PERIYOT)).padStart(13)}` + `${String(p.yeniden * YENIDEN_SN + p.sil * SIL_SN).padStart(13)}`); } console.log("\nkapanan bolgenin kendi partileri zaten toplanmiyor;"); console.log("yukaridaki kayip dokuz saglam bolgenin kaybidir.");
dogu_2 kapandi — ayni gercek degisiklik, uc kayit bicimi bicim yeniden hizmet disi makine-sn kacan parti uygulama sn elle on blok 0 0 0 10 sayi temelli 5 525 35 560 kume temelli 0 0 0 10 kapanan bolgenin kendi partileri zaten toplanmiyor; yukaridaki kayip dokuz saglam bolgenin kaybidir.
Sayılar ölçüm ağı biriminde okunduğunda karar netleşir. Kapanan bölgenin makinesi zaten gidecekti; üstteki kayıp sağlam duran dokuz bölgenin kaybıdır. Sayı temelli biçimde beş sağlam makine 105’er saniye hizmet dışı kalır: 525 makine-saniye ve 35 kaçan sayaç partisi. Elle ve küme temelli biçimlerde bu kalemler sıfırdır. Uygulama süresi de 560 saniyeye karşı 10 saniyedir.
Kaçan parti geri gelmez. Sayaçlar okumayı sürdürür ama o pencerede kimse çekmediği için ölçüm ağının o beş bölgesinde 105 saniyelik bir boşluk oluşur — ve bu boşluğun kaydında hiçbir iz yoktur. Kayıt doğru, plan doğru, uygulama doğru; kaybolan yalnız veridir.
Bu bölümün kapanışında kaydın kapsamadığı bir kalem adıyla anılmalıdır: bölge listesinin kendisi. Kayıtta on bölge adı yazılıdır, ama hangi bölgede sayaç olduğu kaydın bildiği bir şey değildir — saha ekibinin tuttuğu bir listeden elle kopyalanmıştır. Bir bölge kapandığında kayıt bunu kendiliğinden öğrenmez; biri gidip listeden siler. Kaydın en pahalı kalemi olan bu değişikliğin tetikleyicisi, kaydın tamamen dışındadır.
Kayıt Biçimi Kararı
| Biçim | Satır (10 kaynak) | Ortadan çıkarmada kalem | Kayan adres | İstisna dalı | Ne zaman |
|---|---|---|---|---|---|
| Elle on blok | 50 | 1 | 0 | 0 | Kaynaklar birbirinden gerçekten farklıysa |
| Sayı temelli | 7 | 6 | 5 | istisna başına 1 | Sırası anlamsız, yalnız sondan büyüyen küme |
| Küme temelli | 18 | 1 | 0 | 0 | Elemanların kimliği olan küme |
Tablo tek bir ölçüyle özetlenir: satırdan tasarruf etmenin fiyatı adres kararlılığıdır. Sayı temelli biçim elle yazımın 50 satırını 7’ye indirir — yedi kat — ve karşılığında ortadaki her değişiklikte beş ile altı arasında gereksiz yeniden oluşturma üretir. Küme temelli biçim 18 satırla elle yazımın üçte birine iner ve adres kararlılığını hiç kaybetmez; ödediği bedel, bölge adlarının kayıtta ikinci kez, harita anahtarı olarak yazılmasıdır.
Karar üç biçim arasında değil, iki soru arasındadır. Birincisi: bu on kaynak birbirinin kopyası mı,
yoksa her birinin kendi kimliği mi var? Ölçüm ağında ikincisi doğrudur — dogu_2 bir sıra numarası
değil, sahada duran bir bölgedir. İkincisi: bu küme ortasından değişir mi? Bölge listesi kapanmalar
ve açılmalarla değişir, yani değişir. İki cevap birlikte küme temelli biçimi işaret eder; sayı
temelli biçim buradaki 7 satırı 18 satıra tercih ettirecek kadar ucuz değildir.
Özet
- Üç kayıt biçimi de aynı 10 gerçek kaynağı aynı niteliklerle üretiyor; fark gerçekte değil, kaydın kaynağa verdiği adrestedir.
- Satır: elle 50, küme temelli 18, sayı temelli 7. İstisna sayısı 3’e çıkınca sayı temelli biçimde tek ifadede 3 iç içe koşul birikir, diğer ikisinde dal sayısı 0 kalır.
dogu_2kapandığında elle ve küme temelli biçim 1 kalem, sayı temelli biçim 6 kalem üretti; 5 adres başka bir gerçek kaynağa kaydı. Ortaya bölge girmesinde sayılar 1’e karşı 7 ve 6 oldu.- Sona ekleme üç biçimde de 1 kalem: sayı temelli yineleme, sırası anlam taşımayan ve yalnız sondan büyüyen kümeler için doğru biçimdir.
- Plan yanılmadı — “5 yeniden oluşturulacak” dedi ve 5’i yeniden oluşturuldu, oran 5/5. Beklenti ile plan arasındaki 5 kalemlik fark kayıt biçiminden doğdu.
- Ölçüm ağı biriminde: 5 sağlam makine 105’er saniye hizmet dışı, 525 makine-saniye, 35 kaçan sayaç partisi, 560 saniyelik uygulama — küme temelli biçimde hepsi 0 ve 10 saniye.
Sonraki Adım
Bu ders plan kalemlerini saydı ama planı hep hazır kabul etti: kalemler bir yerden geliyordu. Sonraki ders o yeri kurar — kayıt ile durumu karşılaştırıp kalem kalem ekle, değiştir, yeniden oluştur ve sil kararını üreten planlayıcının kendisini yazar. Ölçülecek şey planın kendi doğruluğudur: kaç kalem planda yok ama uygulamada oluyor, kaç kalem planda olup gerçekleşmiyor, ve “yeniden oluşturulacak” denilen kalemlerin kaçı gerçekten yeniden oluşturuluyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.