Proqramlaşdırmada Generatorlar

Abbas Majidov
4 min readNov 30, 2024

--

Photo by Austris Augusts on Unsplash

Ü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?

Photo by Karim MANJRA on Unsplash

Ə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

Kollatz fərziyəsinin vizualizasiyası (p5.js)

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.jsChart.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!

Sign up to discover human stories that deepen your understanding of the world.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

No responses yet

Write a response