Proqramlaşdırmada Generatorlar
Ümumi məlumat
Proqramlaşdırmada generatorlar — hər bir icra zamanı əvvəlki dəyərini bərpa edərək, bu dəyəri növbəti dəyərin emalında istifadə edə bilən altproqramdır.
Generator funksiya adi funksiyalara bənzəyir; onun da parametrləri var, adi funksiya kimi çağırılır və məlumatları emal edir. Ancaq generatorun icrası fasiləsiz deyil. Yəni, məsələn hər hansı bir sıranın bütün elementlərinə tətbiq edilməli olan əməliyyatlar, adi funksiyadan fərqli olaraq növbə ilə aparılacaq. Belə olan təqdirdə, daha az yaddaş tələb olunur və əməliyyatlara nəzarət daha rahat olur.
Generatorlar necə işləyir?
Əksər proqramlaşdırma dilləri generator-funksiyaları dəstəkləyir. Ümumi olaraq, hər bir generator-funksiya Iterator interfeysini implementasiya etməklə, aşağıdakı abstraksiyalardan ibarətdir:
state // Generator funksiyanın cari vəziyyətini ehtiva edir
next // Generator funksiyanın növbəti iterasiyasının nəticəsi
Gəlin, əvvəlcə JavaScript proqramlaşdırma dili ilə yazılmış aşağıdakı primitiv generator-funksiya nümunəsinə nəzər yetirək:
// JS-də generator-funksiyalar * suffiksi ilə yaradılmalıdır
function* counter(startPoint) {
while(true) yield startPoint++;
}
const count = counter(1);
console.log(count.next().value); // 1
console.log(count.next().value); // 2
console.log(count.next().value); // 3
Göründüyü kimi, counter adlı funksiyanın daxilində sonsuz dövrdə davam edən inkrementasiya əməliyyatı yerinə yetirilir. Analoji alqoritmi adi funksiyalar ilə reallaşdırmaq mümkün deyil. Lakin, generator-funksiyalar icra-kontekstini mərhələli şəkildə apardığı üçün iterasiya əməliyyatı düzgün şəkildə yerinə yetiriləcək. Burada, hər bir icra nəticəsi yield vasitəsilə (əksər proqramlaşdırma dillərində olduğu kimi) geri qaytarılır.
İndi isə gəlin, PHP proqramlaşdırma dili ilə yazılmış digər bir nümunəyə nəzər yetirək:
<?php
$file_handle = fopen('https://gist.githubusercontent.com/kevin336/acbb2271e66c10a5b73aacf82ca82784/raw/e38afe62e088394d61ed30884dd50a6826eee0a8/employees.csv', 'r');
function get_all_lines($file_handle) {
while (!feof($file_handle)) {
yield fgets($file_handle);
}
}
function search($keyword) {
global $file_handle;
foreach(get_all_lines($file_handle) as $index => $line) {
if(strpos($line, $keyword)) {
echo "Found {$keyword} at line {$index}";
break;
}
}
}
search('Steven'); // Found Steven at line 10
?>
Bu nümunədə, faylın oxunması və axtarış əməliyyatı generator-funksiya vasitəsilə sətir-sətir yerinə yetirilir.
Praktiki nümunə — Kollatz fərziyəsi

Son olaraq, gəlin öyrəndiklərimizə əsaslanaraq, maraqlı bir problemin — Kollatz fərziyəsinin realizasiyasını yerinə yetirək.
Alman riyaziyyatçısı olan Lotar Kollatz (Lothar Collatz) 1937-ci ildə, 27 yaşında ikən bu fərziyyəni irəli sürmüşdür və fərziyəni hələ də isbat edən olmamışdır:
Hər hansı bir müsbət tam (natural) ədədi:
1. Cütdürsə, 2-ə bölmək;
2. Təkdirsə, 3-ə vurub üzərinə 1 əlavə etmək;
əməliyyatlarını periodik şəkildə yerinə yetirsək, son ədəd mütləq 1 olacaqdır.
Nəticədə, bu fərziyənin şərtlərinə uyğun olaraq, hər hansı bir natural ədədin hansı mərhələdə Kollatz fərziyəsinə “tab gətirə bilmədiyini” görəcəyik 😉
Əvvəlcə solver adlı obyektin yaradılması ilə başlayaq:
Nəzərə alın ki, burada oxuyucunun JS-kod blokunda istifadə olunan əsas anlayışları bildiyi güman edilir.
const solver = {
numbers: [],
results: [],
loops: null,
data: [],
// Generator
*calculate(initialValue) {
yield initialValue;
while (true) {
/*
* Cütdürsə, 2-ə bölmək;
* Təkdirsə, 3-ə vurub üzərinə 1 əlavə etmək;
*/
yield initialValue % 2 == 0 ?
(initialValue /= 2) :
(initialValue = 3 * initialValue + 1);
}
},
set number(data) {
if (!Array.isArray(data) && isNaN(Number(data)))
throw new Error("Number is NaN");
for (const value of Array.isArray(data) ? data : [data]) {
if (isNaN(value) || value == 0) continue;
this.numbers.push(value);
this.results.push(this.calculate(value));
this.loops = new Array(this.results.length).fill([0]);
chart.data.datasets.push({
label: `${value} - LoopCount(0)`,
borderColor: this.color,
backgroundColor: "transparent",
});
}
},
get color() {
const letters = "0123456789ABCDEF";
let color = "#";
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
},
};
İndi isə gəlin solver-i vizuallaşdıraq. Bunun üçün p5.js və Chart.js kitabxanalarından istifadə edəcəyik.
let frameRateCount = 10
function setup() {
noCanvas();
frameRate(frameRateCount);
solver.number = floor(random(5, 10000));
}
function draw() {
for (const index in solver.results) {
// Generatorun nəticəsi
const result = solver.results[index].next().value;
if (!Array.isArray(solver.data[index])) solver.data[index] = [];
solver.data[index].push(result);
if(![1,2,4].includes(result)) solver.loops[index]++;
}
for (const index in solver.data) {
const data = solver.data[index];
chart.data.labels = data;
chart.data.datasets[index].label = chart.data.datasets[index].label.replace(/(.*?-.*?)\d+/, `$1${solver.loops[index]}`)
chart.data.datasets[index].data = data;
}
chart.update();
}
Kodlar buradadır. Ümid edirəm faydalı oldu. Oxuduğunuz üçün təşəkkür edirəm!