CodeGym /Kurslar /C# SELF /Funksional proqramlaşdırmaya giriş

Funksional proqramlaşdırmaya giriş

C# SELF
Səviyyə, Dərs
Mövcuddur

1. Giriş

Funksional proqramlaşdırma (FP) — bu proqramlaşdırmanın o cür paradigmasıdır ki, əsas tikinti bloku obyekt və ya prosedur/metod deyil, riyazi mənada funksiya-dır. FP-də əsas diqqət "nə hesablamaq"-a, nəinki "necə hesablamaq"-a verilir.

Siz artıq lambda-ifadələrlə və LINQ-lə işləyərkən FP-nin ayrı-ayrı ideyalarıyla qarşılaşmısınız. Amma fərq nədir? Praktikada: OOP obyektləri və onların qarşılıqlı təsirini təsvir edir, prosedural proqramlaşdırma — addımlar toplusu, FP isə — funksiyaların kompozisiyası, davranışı dəyər kimi ötürmək, vəziyyətin dəyişməsindən imtina (immutability) və yan effektlərin olmamasıdır.

Niyə yeni paradigma lazımdır?

  • Daha təmiz, proqnozlaşdırıla bilən və test edilə bilən kod.
  • Çoxiprosessli dəstəyin sadələşdirilməsi ("heç bir vəziyyət yoxdur — heç bir problem yoxdur").
  • Qısa və ifadəli kod (neçə az kod — o qədər az səhv).
  • Yüksək səviyyəli, asan təkrar istifadə oluna bilən abstraksiyalar.

Analojiya

Təsəvvür edin ki, restoran sifariş alıb: "omelet hazırla". İmperativ aşbaz təlimat siyahısını yerinə yetirir: yumurta götür, qır, çal, qızart. Funksional aşbaz deyir: res = omlet(yumurta) — o funksiyalarla işləyir, mətbəxin daxili vəziyyətindən abstraksiya edir (yaxşı, təxminən).

C#-da hər iki yanaşmadan istifadə edə bilərsiniz. Bu dili real layihələr üçün çox çevik və güclü edir.

FP-nin əsas anlayışları

1. Higher-order funksiyalar

Funksiyaları parametr kimi ötürmək, digər funksiyalardan qaytarmaq və dəyişənlərdə saxlamaq olar. Siz bunu lambda-ifadələrlə və delegatlarla artıq etmisiniz. FP-də belə "funksiyalar üzərində funksiyalar" hər şeyin əsasını təşkil edir.

2. Təmiz funksiyalar

Funksiya "təmiz" sayılırsa, onun nəticəsi yalnız parametrlərdən asılıdır və o özündən kənarda heç nəni dəyişmir (heç bir yan effekt yoxdur). Eyni arqumentlə iki dəfə çağırış həmişə eyni nəticəni verir.

3. Dəyişməzlik (Immutability)

Məlumat "yerində" dəyişdirilmir: yeni vəziyyət — yeni obyektdir. Bu proqram haqqında düşünməyi asanlaşdırır və çoxiprosessli proqramlarda kömək edir.

4. Yan effektlərin olmaması

Funksiya fayla yazmır, qlobal dəyişəni dəyişmir, ekrana çəkmir — sadəcə nəticəni qaytarır. Real həyatda yan effektlər qaçılmazdır, amma onları sistemin kənarlarında izolyasiya etməyə çalışırlar.

5. Funksiyaların kompozisiyası

Bir funksiyanı digərindən qurmaq olar, bloklar kimi. Məsələn: müsbət ədədləri filtrə sal, onların kvadratlarını götür və cəmlə. Hər əməliyyat ayrı funksiyadır və asanlıqla birləşir (Where → Select → Sum).

2. FP C#-da: nəzəriyyədən praktika

C# — multiparadigmalı dil: OOP-u, prosedural yanaşmanı və güclü funksional stilini (lambda-lar, delegatlar, extension metodlar və LINQ) yaxşı dəstəkləyir.

Tədris tətbiqimiz nümunəsində araşdıraq

Tutaq ki, ədədlər və sətrlər siyahısı ilə işləyən proqram üzərində işləyirik. Tapşırığımız — bu məlumatlara funksional tərzdə müxtəlif əməliyyatlar tətbiq etmək.

Nümunə 1: Higher-order funksiyaların istifadəsi


// Siyahının bütün elementlərinə action tətbiq edir
public static void ForEach<T>(List<T> items, Action<T> action)
{
    foreach (var item in items)
    {
        action(item);
    }
}

İstifadəsi:


var numbers = new List<int> { 1, 2, 3, 4, 5 };
ForEach(numbers, n => Console.WriteLine(n * n)); // Parametr-funksiya

Görürsünüz? Funksiyanı dəyişəndə saxlamaq və ya adi dəyər kimi ötürmək olar — elə bil mətbəxdə alma verir kimi!

Nümunə 2: Təmiz funksiya

Proqramın vəziyyətini dəyişməyən və yalnız girişdən asılı funksiya:


int MultiplyByTwo(int x)
{
    return x * 2;
}
  • Xaricdən heç nə ilə asılı deyil.
  • Xarici heç nəni dəyişmir.
  • x = 5 üçün həmişə 10 qaytarır.

Müqayisə üçün funksiyaya baxın ki, qlobal dəyişəni istifadə edir və dəyişdirir:


int total = 0;
int AddToTotal(int x)
{
    total += x;
    return total;
}

Bu artıq təmiz funksiya deyil — nəticə xarici vəziyyətdən asılıdır və onu dəyişdirir.

Nümunə 3: Məlumatların dəyişməzliyi

Giriş məlumatlarını dəyişdirmək əvəzinə yeni nümunələr yaradırıq:


List<int> AddOneToEach(List<int> numbers)
{
    return numbers.Select(n => n + 1).ToList();
}

Giriş siyahısı ümumiyyətlə dəyişmir. Çoxiprosessli proqramlarda bu xüsusilə faydalıdır: daha az lock və data race.

Nümunə 4: Funksiyaların kompozisiyası

Bütün cüt ədədlərin kvadratlarının cəmini alın:


int SumOfEvenSquares(List<int> numbers)
{
    return numbers
        .Where(n => n % 2 == 0)     // Yalnız cütləri saxla
        .Select(n => n * n)         // Kvadratlaşdır
        .Sum();                     // Cəmlə
}

Oxunaqlı və deklarativ: hər bir əməliyyat ayrı funksiyadır.

3. Faydalı məqamlar

FP, LINQ və C#

LINQ — kolleksiyalar üçün demək olar ki "FP praktikasıdır": burada higher-order funksiyalardan istifadə edirsiniz (Where, Select və s.), yeni ardıcıllıqlar əldə edirsiniz, ilkinləri mutasiya etmədən və hər dönüşüm ayrı ifadədir. Nəticə — IEnumerable<T>, hansının ki nə almaq istədiyinizi, nəyi deyil, necə iterasiya etməyi təsvir edir.

Cədvəl analoqları

İmperativ (prosedural/OOP) Funksional (LINQ/FP-stil)
foreach (var x in xs) ...
xs.Select(...)
Kolleksiyanı "mutasiya etmək" Yeni kolleksiya almaq
Vəziyyət (total += x) Təmiz funksiyalar (xs.Sum())
Necə etmək: «bunları et» Nə istədiyimizi təsvir etmək: «nə almaq istəyirik»

FP vs OOP: iki dünya — bir C#

Bu rəqib düşərgələr deyil. Real C# layihələrində onları qarışdırırlar: domain model-i siniflərlə (OOP) qurmaq rahatdır, kolleksiyaların işlənməsi, data aggregasiyası və transformasiyalar isə funksional stilində LINQ, lambda-lar və extension metodlar vasitəsilə aparılır.

Delegatlar haqda bilikləriniz birbaşa faydalıdır: Func<T, TResult>, Predicate<T>, Action<T> — FP-stilinin tipik tikinti bloklarıdır.

Universal filter funksiyası:


List<T> Filter<T>(List<T> items, Predicate<T> predicate)
{
    var result = new List<T>();
    foreach (var item in items)
    {
        if (predicate(item))
            result.Add(item);
    }
    return result;
}

Çağırışlar:


var adults = Filter(people, person => person.Age >= 18);
var bigFiles = Filter(fileNames, name => name.EndsWith(".mp4") && name.Length > 10);

Fərqli şərtlərlə bir çox oxşar metod yazmaqdansa — bir universal funksiya.

İşəgötürənlər və müsahibələr üçün niyə FP tərzində inkişaf etmiş geliştiricilər?

  • FP kiçik kod bloklarını bütün sistemi qaldırmadan test etməyə kömək edir.
  • Loqikanı saxlamaq daha asandır: vəziyyət azdırsa, səhv mənbəyi də azdır.
  • Paralel və asynchronous kod yazmaq daha asandır — qlobal vəziyyət yoxdur, data race-lər daha az olur.

Necə "fanatik olmamaq" lazımdır?

Bəli, FP güclüdür. Amma C# tamamilə funksional dil deyil və hər məsələ ideal təmizlik tələb etmir. Lazımi yerlərdə lokal dəyişənlərdən və ağlabatan mutasiyalardan qorxmayın. Əsas odur ki, oxunaqlıq, proqnozlaşdırıla bilənlik və test edilə bilmə olsun. FP elementləri — vasitədir, inanclıq deyil.

4. Yeni başlayanların tipik səhvləri

Funksional görsənən, amma əslində funksional olmayan kod üçün çox asan tələyə düşmək olar.

Məsələn, funksiya yeni kolleksiya qaytarır, amma içində yolu üzrə ilkin siyahını mutasiya edir — bu immutability prinsipini pozur və çağıran kodun gözləntilərini pozur.

Başqa misal: lambda ifadəsi xarici dəyişənə müraciət edir və onu dəyişir. Funksional paradigmada bu yan effekt sayılır və kodun davranışını daha az proqnozlaşdırıla bilən edir.

C# kompilyatoru sizi dayandırmayacaq: dil həm birini, həm də o birini etməyə imkan verir. Buna görə FP-praktikalarda diqqətli olmaq lazımdır ki, funksiya "öz-özünə yaşasın", xaricdə heç nəyi dəyişməsin və yalnız arqumentlərini oxusun.

2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
Siyahının filtrasiya funksiyası
Siyahının filtrasiya funksiyası
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION