ბიბლიოთეკა
00/07 · ~32 წთ
GUIDEDECK · კოდისთვის, რომელზეც ადვილად მსჯელობთ

ფუნქციური პროგრამირება
— აზროვნება მნიშვნელობებით,
და არა ნაბიჯებით.

32-წუთიანი სამუშაო სესია ფუნქციურ ინსტრუმენტებზე, რომლებიც ყველა დეველოპერს დღესვე გამოადგება — სუფთა ფუნქციები, უცვლელობა, map/filter/reduce, კომპოზიცია, closure-ები და არარსებობის მოდელირება Option/Result-ით — JavaScript-ისა და TypeScript-ის ჭრილში, გულახდილი შენიშვნებით იმაზე, როდის იმარჯვებს უფრო მარტივი გზა.

~32 წთდამწყები → საშუალოJS / TS მაგალითები
გადაახვიეთ
01 · რა არის FP 4 წთ

პროგრამა უბრალოდ მონაცემია,
რომელიც ფუნქციებში მიედინება.

ფუნქციური პროგრამირება ნაკლებად ენაზეა და მეტად ჩვევაზე: ააგეთ ლოგიკა პატარა სუფთა ფუნქციებისგან — ნაწილებისგან, რომლებიც მნიშვნელობებს იღებენ და მნიშვნელობებს აბრუნებენ, შუალედში კი ჩუმად არაფერს აკეთებენ. თუ ეს გამოგივიდათ, კოდი პროგნოზირებადი, ტესტირებადი და უსაფრთხოდ გადასატანი ხდება. ეს OOP & არქიტექტურის პარადიგმული ბიძაშვილია; რეალური კოდის ბაზების უმეტესობა ორივეს აზავებს.

სუფთა ფუნქცია — ფუნქცია, რომლის შედეგიც მხოლოდ მის შესატან მნიშვნელობებზეა დამოკიდებული და რომელიც თავის გარეთ არაფერს ცვლის. გამოიძახეთ იგივე არგუმენტებით და ყოველთვის იმავე პასუხს მიიღებთ — არანაირი სიურპრიზი, დამალული საათში, მონაცემთა ბაზაში ან გლობალურ ცვლადში.

ორი დაპირება, რომელსაც სუფთა ფუნქცია იძლევა

  • ერთი და იგივე შესატანი → ერთი და იგივე შედეგი. არც დროს კითხულობს, არც შემთხვევით რიცხვს და არც გლობალურ ცვლადს, რომელიც შესაძლოა შეცვლილიყო.
  • გვერდითი ეფექტების გარეშე. გვერდითი ეფექტი ყველაფერია, რასაც ფუნქცია მნიშვნელობის დაბრუნების გარდა აკეთებს — არგუმენტის შეცვლა, დისკზე ჩაწერა, ლოგირება, ქსელის გამოძახება.
  • ერთად ისინი რეფერენციულ გამჭვირვალობას იძლევა: გამოძახება მისივე შედეგით შეგიძლიათ ჩაანაცვლოთ და პროგრამა იდენტურად მოიქცევა. სწორედ ამიტომ არის სუფთა კოდზე მსჯელობა და მისი ტესტირება ასე ადვილი.

სუფთა ფუნქცია მხოლოდ შესატან მნიშვნელობებს ასახავს შედეგზე. არასუფთა კი გლობალურ ცვლადსაც ეხება და I/O-საც აკეთებს — წყვეტილი ისრები გვერდითი ეფექტებია.

არასუფთა — პასუხს ისტორია წყვეტს
let total = 0                 // shared state
function addToCart(n: number) {
  total += n                // mutates the outside world
  console.log(total)         // I/O side effect
}
// call it twice, get different results — hard to test
სუფთა — პასუხს მხოლოდ შესატანი წყვეტს
function addToCart(cart: number, n: number): number {
  return cart + n          // nothing outside is touched
}
addToCart(10, 5)   // 15 — always, no matter when
// trivially testable: feed inputs, check the output

თითქოს  სავაჭრო ავტომატი — დააჭირეთ B4-ს და ყოველთვის იმავე სნეკს მიიღებთ. ფუნქცია, რომელიც გარეთ ამინდზეა დამოკიდებული, სავაჭრო ავტომატი კი არა, განწყობაა.

რეალობის შემოწმება — პროგრამა ნულოვანი გვერდითი ეფექტებით არაფერ სასარგებლოს არ აკეთებს; ადრე თუ გვიან მან სტრიქონი უნდა შეინახოს ან ეკრანი დახატოს. ფუნქციური მიზანი ეფექტების აკრძალვა კი არა, მათი კიდეებში გაწევაა — შუაში კი დიდი, სუფთა და ადვილად სატესტი ბირთვი რჩება.
02 · უცვლელობა 4 წთ

ნუ შეცვლით მნიშვნელობებს —
ჩაანაცვლეთ ისინი.

ბაგების, რომლებზეც ამბობენ "წამის წინ ხომ მუშაობდა", ყველაზე დიდი წყარო საერთო ცვალებადი მდგომარეობაა: პროგრამის ორი ნაწილი ერთსა და იმავე ობიექტს იჭერს, ერთი ჩუმად ცვლის მას, მეორე კი ფუჭდება. ფუნქციური გამოსავალი უცვლელობაა — მოეპყარით მნიშვნელობებს როგორც read-only-ს და ძველის შეცვლის ნაცვლად ააგეთ ახალი მნიშვნელობა.

უცვლელობა — როგორც კი მნიშვნელობა შეიქმნა, ის აღარასდროს იცვლება; "განახლება" სრულიად ახალ მნიშვნელობას ქმნის და ორიგინალს ხელუხლებლად ტოვებს. იგივე იდეა კვებავს პროგნოზირებად UI მდგომარეობას — იხილეთ მდგომარეობის მართვა, სადაც სწორედ უცვლელი განახლებები აძლევს ხედს იმის ცოდნას, ზუსტად რა შეიცვალა.
prices
[ 10, 20 ]
report
[ 10, 20 ]
[ 10, 20, 2 ]
prices
საერთო · მუტაცია ჟონავს
აქ .push() ორივეს ტეხს
ასლი · თითოეული უსაფრთხოა

ზემოთ: ორი სახელი ერთსა და იმავე მასივზე მიუთითებს, ამიტომ მუტაცია ჟონავს. ქვემოთ: განახლება ახალ მასივს აბრუნებს და ორიგინალი ხელუხლებელი რჩება.

რატომ არის საერთო მუტაცია საზიანო

  • ალიასინგი. ენების უმეტესობაში ობიექტის გადაცემისას გადაეცემა მიმართვა, და არა ასლი. ორი ცვლადი შეიძლება ერთი და იგივე რამ იყოს, ორი სახელით.
  • მოქმედება მანძილიდან. შეცვალეთ ერთი სახელით და ცვლილებას ყველა დანარჩენი სახელი დაინახავს — ხშირად ის კოდიც, რომელმაც არც კი იცოდა, რომ მნიშვნელობას სხვასთან იზიარებდა.
  • დროზე დამოკიდებული ბაგები. მნიშვნელობა ახლა იმაზეა დამოკიდებული, ვინ და როდის გაუშვა. სწორედ ეს არაპროგნოზირებადობაა, რომლის მოკვლასაც სუფთა ფუნქციები ცდილობდნენ.

უცვლელობა ბაგების მთელ ამ კლასს აქრობს: თუ ადგილზე ვერაფერს შეცვლიან, ვერავინ შეცვლის მას თქვენს ზურგს უკან.

ცვლის გამომძახებლის მასივს
const prices = [10, 20]
function applyTax(arr: number[]): number[] {
  arr.push(arr[0] * 0.2)   // edits the original!
  return arr
}
applyTax(prices)
// prices is now [10, 20, 2] — a surprise mutation
აბრუნებს ახალ მასივს
const prices = [10, 20]
function withTax(arr: number[]): number[] {
  return [...arr, arr[0] * 0.2]  // fresh copy
}
const taxed = withTax(prices)
// prices stays [10, 20]; taxed is the new value
განა კოპირება ნელი არაა? გულუბრყვილო მიდგომით — დიახ. ნამდვილი ფუნქციური ენები (და ბიბლიოთეკები, როგორიცაა Immer ან Immutable.js) იყენებენ სტრუქტურულ გაზიარებას: ახალი მნიშვნელობა ძველის უცვლელ ნაწილებს ხელახლა იყენებს და მხოლოდ იმას გამოყოფს, რაც მართლა განსხვავდება — ასე რომ "განახლება" ერთ ბილიკს აკოპირებს და არა მთელ ხეს.
03 · მაღალი რიგის ფუნქციები 5 წთ

აღწერეთ, რა გინდათ,
და არა ციკლი, რომლითაც ამას მიიღებთ.

მაღალი რიგის ფუნქცია ფუნქციას იღებს არგუმენტად (ან ფუნქციას აბრუნებს). ეს ერთი იდეა ხსნის ყოველდღიური FP-ის მუშა ცხენებს: map, filter და reduce — სამი სამშენებლო ბლოკი, რომელიც ხელით დაწერილი ციკლების უმეტესობას ცვლის კოდით, რომელიც თავად მოთხოვნასავით იკითხება.

მაღალი რიგის ფუნქცია (HOF) — ფუნქცია, რომელიც სხვა ფუნქციას იღებს ან აბრუნებს. ფუნქციას, რომელსაც გადასცემთ, callback ჰქვია. რადგან FP-ში ფუნქციები უბრალოდ მნიშვნელობებია, ქცევის გადაცემა ისევე შეგიძლიათ, როგორც რიცხვებისა და სტრიქონების.
map

თითოეულის გარდაქმნა

გაუშვით ფუნქცია ყველა ელემენტზე და შეაგროვეთ შედეგები. სიგრძე იგივე რჩება, თითოეული ელემენტი კი ფორმას იცვლის.

[1,2,3].map(n => n * 2)
// [2, 4, 6]
filter

ნაწილის დატოვება

დატოვეთ მხოლოდ ის ელემენტები, რომლებზეც შემოწმება true-ს აბრუნებს. იგივე ელემენტები, უბრალოდ ნაკლები.

[1,2,3,4].filter(n => n % 2 === 0)
// [2, 4]
reduce

ერთში დაკეცვა

გაიარეთ სია აკუმულატორით ხელში და გზადაგზა შეაერთეთ. შედის ბევრი, გამოდის ერთი მნიშვნელობა.

[1,2,3].reduce((a,b) => a+b, 0)
// 6
1
2
3
2
4
6
1
2
3
4
2
4
1
2
3
6
map · თითოეულს ცვლის
filter · ნაწილს ტოვებს
reduce · ერთში კეცავს

map რაოდენობას ინარჩუნებს და ფორმას უცვლის; filter კვეცავს; reduce კი მთელ სიას ერთ მნიშვნელობამდე კუმშავს.

მოგება: დააჯაჭვეთ ისინი

რადგან თითოეული მნიშვნელობას აბრუნებს, მათი ერთმანეთში გადაბმა შეგიძლიათ. ჯაჭვი ზემოდან ქვემოთ წინადადებასავით იკითხება — და აღარაა არც ინდექსი, არც დროებითი მასივი და არც ერთით აცდენა, რომელშიც შეიძლება შეცდეთ.

  • აღრიცხვა აღარ გჭირდებათ. ციკლს, მრიცხველსა და აკუმულატორს თქვენს ნაცვლად უვლიან.
  • კომპოზირებადი. თითოეული ნაბიჯი დამოუკიდებელია; ნაბიჯები გადაალაგეთ ან ჩაამატეთ დანარჩენებზე ხელის ხლების გარეშე.
  • განზრახვის მიმართ გულახდილი. "დატოვე გადახდილი შეკვეთები, აიღე მათი ჯამები, შეკრიბე ისინი" პირდაპირ კოდშივე წერია.
იმპერატიული — როგორ, ნაბიჯ-ნაბიჯ
const out: number[] = []
for (let i = 0; i < orders.length; i++) {
  if (orders[i].paid) out.push(orders[i].total)
}
let sum = 0
for (let i = 0; i < out.length; i++) sum += out[i]
// correct, but the intent is buried in plumbing
დეკლარაციული — რა, სამ სვლაში
const sum = orders
  .filter(o => o.paid)          // keep some
  .map(o => o.total)            // transform each
  .reduce((a, b) => a + b, 0)  // fold to one
// reads like the requirement out loud

თითქოს  სამზარეულოს ხაზი — ერთი სადგური ჭრის (map), მეორე ცუდ ნაჭრებს აგდებს (filter), მესამე კი ყველაფერს ერთ კერძად აწყობს (reduce).

04 · კომპოზიცია, კარინგი და ნაწილობრივი გამოყენება 5 წთ

ააგეთ დიდი ქცევა
პატარა, ერთმანეთში ჩამჯდარი ნაწილებისგან.

თუ სუფთა ფუნქციები აგურებია, კომპოზიცია დუღაბია: შეაერთეთ პატარა ფუნქციები ისე, რომ ერთის შედეგი შემდეგის შესატანად იქცეს. კარინგი და ნაწილობრივი გამოყენება ის ხერხებია, რომლებიც ფუნქციების შეერთებას აადვილებს — არგუმენტების ნაწილ-ნაწილ მიწოდების საშუალებით.

ფუნქციების კომპოზიცია — ორი ან მეტი ფუნქციის შეერთება ისე, რომ ერთის შედეგი შემდეგის არგუმენტად იქცეს. compose(f, g)(x) ნიშნავს f(g(x))-ს; pipe იგივე იდეაა, ოღონდ მარცხნიდან მარჯვნივ იკითხება, რაც ჩვეულებრივ ემთხვევა იმას, როგორც ჩვენ ნაბიჯებს ვყვებით.
const compose = (f: Function, g: Function) => (x: unknown) => f(g(x))
const pipe = (...fns: Function[]) => (x: unknown) =>
  fns.reduce((v, f) => f(v), x)

const clean = pipe(trim, toLower, dropAccents)
clean("  Café ")   // "cafe"
// each step is tiny, pure, and reusable

პაიპი მონაცემების ასაწყობი ხაზია: მნიშვნელობა თანმიმდევრობით გაივლის ყველა პატარა ფუნქციას.

კარინგი & ნაწილობრივი გამოყენება

კარინგი მრავალარგუმენტიან ფუნქციას ერთარგუმენტიანი ფუნქციების ჯაჭვად გადაწერს: add(a, b) ხდება add(a)(b). ნაწილობრივი გამოყენება სწორედ ის მოგებაა, რასაც ეს გაძლევთ — გამოიძახეთ ახლა ნაწილი არგუმენტებით და მიიღებთ სპეციალიზებულ ფუნქციას, რომელიც მათ დაიმახსოვრებს და დანარჩენებს დაელოდება.

  • სპეციალიზებული ინსტრუმენტები იაფად. add(1) ინკრემენტია; discount(0.5) კი "ნახევარ ფასად".
  • კომპოზიციას ერგება. პაიპებს ერთარგუმენტიანი ფუნქციები სჭირდება — კარინგი ზუსტად ასეთებს აწარმოებს.
  • გულახდილი კომპრომისი: ჭარბმა კარინგმა და "point-free" სტილმა შეიძლება კოდი გაუგებარი გახადოს. მიმართეთ მაშინ, როცა აზუსტებს და არა საჩვენებლად.
// curried: one argument at a time
const add = (a: number) => (b: number): number => a + b
const inc = add(1)        // partial application
inc(10)                   // 11

const discount = (rate: number) => (price: number): number =>
  price * (1 - rate)
const half = discount(0.5)   // "half off" tool
half(80)                  // 40

მიაწოდეთ ახლა არგუმენტების ნაწილი; სანაცვლოდ მიიღებთ მზა ფუნქციას, რომელიც მათ მოგვიანებისთვის იმახსოვრებს.

05 · closure-ები და რეკურსია 5 წთ

ფუნქციები, რომლებიც იმახსოვრებენ,
და ფუნქციები, რომლებიც იმეორებენ.

ორი მექანიზმი ამუშავებს ფუნქციურ ინსტრუმენტთა ნაკრებს. closure ფუნქციას საშუალებას აძლევს კლასის გარეშე ატაროს პირადი მდგომარეობა. რეკურსია კი აძლევს საშუალებას თქვას "გააკეთე ეს, მერე დანარჩენს იგივე უყავი" ცვალებადი ციკლის მრიცხველის გარეშე. ორივე ერთსა და იმავე იდეას ეყრდნობა: ფუნქცია მნიშვნელობაა, რომლის დაჭერაც, გადაცემა და ხელახლა გამოყენებაც შეგიძლიათ.

closure — ფუნქცია იმ ცვლადებთან ერთად, რომლებიც მან იქიდან დაიჭირა, სადაც აღიწერა. მას შემდეგაც კი, რაც გარე ფუნქცია დაბრუნდება, შიდა ფუნქცია ცოცხალ კავშირს ინარჩუნებს ამ ცვლადებთან — და პირად, მდგრად მდგომარეობას გაძლევთ ისე, რომ ობიექტი არსად ჩანს.
function counter(): () => number {
  let n = 0             // captured by the inner fn
  return () => ++n        // closes over n
}
const next = counter()
next()   // 1
next()   // 2 — n survives between calls, stays private
counter()-ის scope
n = 2
next
() => ++n
next() კვლავ წვდება n-ს — n პირადია

next იჭერს n-ს იმ scope-იდან, სადაც დაიბადა — სხვა ვერავინ ვერც დაინახავს და ვერც შეეხება.

რეკურსია — ფუნქცია, რომელიც ამოცანას თავისივე გამოძახებით წყვეტს, ოღონდ მის უფრო პატარა ნაწილზე. ყოველ რეკურსიას ორი ნაწილი სჭირდება: საბაზო შემთხვევა, რომელიც ჩაშვებას აჩერებს, და რეკურსიული შემთხვევა, რომელიც ამოცანას ამ ბაზისკენ ამცირებს.
function sum(list: number[]): number {
  if (list.length === 0) return 0   // base case
  const [head, ...rest] = list
  return head + sum(rest)           // recursive case
}
sum([1, 2, 3])   // 6
sum([1,2,3]) = 1 + sum([2,3])
sum([2,3]) = 2 + sum([3])
sum([3]) = 3 + sum([])
sum([]) = 0 ← საბაზო
დახვევა, მერე უკან შეკრება → 6

თითოეული გამოძახება თავს აცლის და დანარჩენს გადადებს, სანამ საბაზო შემთხვევა 0-ს არ დააბრუნებს — მერე კი შეკრებები უკან დაბრუნების გზაზე იხსნება.

გულახდილი დათქმა — რეკურსია ელეგანტურია, მაგრამ JavaScript-ის ძრავების უმეტესობაზე (V8, SpiderMonkey) ღრმა რეკურსია სტეკს გადაავსებს: კუდისებრი გამოძახებების ოპტიმიზაცია სპეციფიკაციაშია, მაგრამ 2026 წლის მდგომარეობით მხოლოდ Safari-ის JavaScriptCore-ში მუშაობს. დიდი შესატანისთვის ჯობია ჩვეულებრივი ციკლი ან ცხადი აკუმულატორი. რეკურსია იქ გამოიყენეთ, სადაც მონაცემები ბუნებრივად ჩალაგებულია (ხეები, JSON) და სიღრმე შემოსაზღვრულია.
06 · არარსებობა და შეცდომები ტიპში 5 წთ

აქციეთ "არაფერი" და "ჩავარდა"
ტიპის ნაწილად.

პროგრამებს ორი ყოველდღიური რამ ანგრევს: მნიშვნელობა, რომელიც შეიძლება არ არსებობდეს, და ოპერაცია, რომელიც შეიძლება ჩავარდეს. იმპერატიული პასუხები — null და throw — უხილავია: ფუნქციის ხელმოწერაში არაფერი გაფრთხილებთ, რომ ეს შეიძლება მოხდეს. ფუნქციური პასუხი ორივეს დაბრუნების ტიპში ცხადად აღწერს, ასე რომ კომპილატორი გაიძულებთ, დაამუშაოთ ისინი.

Option (იგივე Maybe) — მნიშვნელობა, რომელიც ან Some(x)-ია, ან None — ცვლის null-ს. Result (იგივე Either) — ან Ok(value), ან Err(error) — ცვლის ნასროლ გამონაკლისს. ორივე უხილავ შესაძლებლობას ხილულ განშტოებად აქცევს, რომლის დამუშავებასაც ვერ დაივიწყებთ.

თავად დაბრუნების ტიპი ორივე შედეგს ასახელებს — "არაფრისა" და "ჩავარდნის" გზები პირდაპირ ხელმოწერაშივეა.

რატომ სჯობს ეს null-ს & throw-ს

  • არაფერია დამალული. null და გამონაკლისები ტიპში არ ჩანს; Option ან Result კი ჩანს. კომპილატორი თქვენს ჩეკლისტად იქცევა.
  • დავიწყებული შემოწმებები აღარაა. მნიშვნელობას ვერ წაიკითხავთ, სანამ არ გადაწყვეტთ, რა ქნათ მაშინ, როცა ის არ არსებობს ან ოპერაცია ჩავარდა.
  • შეცდომები კომპოზირდება. Result-ები დაჯაჭვადია (map / flatMap): პირველივე ჩავარდნა ჯაჭვს წყვეტს და დანარჩენი გამოტოვდება — try/catch-ების პირამიდის გარეშე.
null / throw — უხილავი ნაღმები
function findUser(id: number) {
  const u = db.get(id)
  return u ?? null      // signature hides the null
}
findUser(7).name        // crashes if it was null
// nothing forced the caller to check
Result — ტიპი განშტოებას გაიძულებთ
type Result<T, E> =
  | { ok: true;  value: T }
  | { ok: false; error: E }

function parsePrice(s: string): Result<number, string> {
  const n = Number(s)
  return Number.isNaN(n)
    ? { ok: false, error: "not a number" }
    : { ok: true,  value: n }
}

თითქოს  ამანათი, რომელიც წარწერით მოდის: ან "შიგთავსი შიგნითაა", ან "მიტანა ჩავარდა: მიზეზი" — ხსნით და წინასწარ იცით, რომ ორივე შედეგი არსებობს, ნაცვლად იმისა, რომ ცარიელმა ყუთმა გაგაკვირვოთ.

07 · FP vs OOP — ორივე კარგად 4 წთ

ეს რელიგია არაა —
ეს ინსტრუმენტების ნაკრებია, რომელსაც ურევთ.

FP და OOP მტრები არ არიან; ისინი სხვადასხვა კითხვას პასუხობენ. OOP მდგომარეობას იმ ქცევასთან ერთად ალაგებს, რომელიც მას იცავს; FP კი მონაცემებსა და ქცევას ჰყოფს და სუფთა გარდაქმნებს ეყრდნობა. 2026 წელს ძლიერი კოდის ბაზების უმეტესობა ჰიბრიდია — ობიექტზე ორიენტირებული ჩონჩხი ფუნქციური ბირთვით.

method()
state
მონაცემი
მონაცემი
f
g
method()
OOP · მდგომარეობა + ქცევა ერთად
ობიექტი თავის მონაცემებს იცავს
FP · მონაცემი ფუნქციებში მიედინება
მონაცემი მარტივია; ქცევა ცალკეა

OOP მონაცემებსა და მის მეთოდებს გარშემო საზღვარს ავლებს; FP კი მონაცემებს მარტივად ტოვებს და სუფთა ფუნქციების ჯაჭვში ატარებს.

როდის რომელი უნდა იყოს წამყვანი

  • დაეყრდენით OOP-ს, როცა დაცული ინვარიანტებისა და ჩანაცვლებადი ქცევის მქონე ერთეულებს მოდელირებთ — იხილეთ OOP & არქიტექტურა. პოლიმორფიზმი იქ ბრწყინავს, სადაც "მრავალი ფორმა, ერთი გამოძახებაა".
  • დაეყრდენით FP-ს მონაცემთა პაიპლაინებზე, გარდაქმნებზე და ყველაფერზე, რისი იზოლირებულად ტესტირებაც ან კონკურენტულობის პირობებში გააზრებაც გსურთ.
  • ჩვეული ნაზავი: ობიექტები/მოდულები კიდეებზე (I/O, ფრეიმვორკის წებო), სუფთა ფუნქციური ბირთვი კი ბიზნეს-ლოგიკისთვის. ეფექტები კიდეებში გაწიეთ; შუაგული სუფთა შეინარჩუნეთ.

ინსტრუმენტების ლანდშაფტი

ფუნქციური კოდის დასაწერად ახალი ენა არ გჭირდებათ. აირჩიეთ იმის მიხედვით, უცვლელობაში რამდენად დიდი დახმარება გჭირდებათ სინამდვილეში.

ჩაშენებული მეთოდები

აირჩიეთ ნაგულისხმევად, ყოველდღიური გარდაქმნებისთვის — ბიბლიოთეკას მაშინ მიმართეთ, როცა ეს აღარ ყოფნის.

  • დადებითი — ჩაშენებულია, map/filter/reduce ყველას უკვე ნაკითხი აქვს, ნულოვანი დამოკიდებულებები.
  • უარყოფითი — ზედაპირულია; ღრმა უცვლელობის დაცვაში არ გეხმარებათ.
Immer

აირჩიეთ ღრმად ჩალაგებული მდგომარეობის განახლებებისთვის (Redux / React-ის reducer-ები).

  • დადებითი — წერთ ჩვეულებრივ "მუტაციურ" კოდს, უცვლელ ასლს კი proxy-ებით იღებთ; პაწაწინა API.
  • უარყოფითი — proxy-ს ჯადოქრობა დანახარჯსაც ამატებს და გასამართავ დამატებით შრესაც.
Ramda

აირჩიეთ მაშინ, როცა მთელ კოდის ბაზაში ნამდვილად ეყრდნობით კარინგსა და კომპოზიციას.

  • დადებითი — ავტომატურად კარირებული, data-last დამხმარეები, კომპოზიციისა და პაიპებისთვის აგებული.
  • უარყოფითი — point-free სტილმა შეიძლება წაკითხვადობა დააზიანოს; კიდევ ერთი შესასწავლი დამოკიდებულება.

შესასწავლად ღირს მაშინაც კი, თუ მათზე არასდროს დაწერთ პროდაქშენს — თითოეული ერთ ფუნქციურ იდეას ზღვრამდე მიჰყავს.

Haskell

აირჩიეთ FP-ის ღრმად შესასწავლად ან ტიპებით მართული დომენებისთვის.

  • დადებითი — წმინდად ფუნქციური, ზარმაცი, ყველაზე ძლიერი მეინსტრიმ ტიპების სისტემა; ფუნქციურ სიმკაცრეს გასწავლით.
  • უარყოფითი — ციცაბო სასწავლი მრუდი; სიზარმაცე მეხსიერების მოულოდნელ ქცევას იწვევს.
Elixir

აირჩიეთ მაღალკონკურენტული, მდგრადი ბექენდ სერვისებისთვის.

  • დადებითი — ფუნქციური BEAM-ზე: მსუბუქი პროცესები, შეცდომებისადმი მდგრადობა, მარტივი კონკურენტულობა.
  • უარყოფითი — დინამიკურად ტიპიზებული; ბიბლიოთეკების ეკოსისტემა უფრო პატარაა.
Clojure

აირჩიეთ მონაცემებით დატვირთული, REPL-ზე აგებული მუშაობისთვის JVM-ზე.

  • დადებითი — Lisp JVM-ზე, ნაგულისხმევად უცვლელი პერსისტენტული მონაცემთა სტრუქტურებით.
  • უარყოფითი — დინამიკური ტიპიზაცია და Lisp-ის სინტაქსი შეჩვევას მოითხოვს; JVM-ის გაშვების დრო.
F#

აირჩიეთ ფუნქციური კოდისთვის, რომელსაც მაინც .NET-ის ეკოსისტემა სჭირდება.

  • დადებითი — პრაგმატული FP .NET-ზე: დისკრიმინირებული გაერთიანებები, პატერნებით შესაბამისობა, სუფთა OOP თავსებადობა.
  • უარყოფითი — C#-ზე პატარა საზოგადოება.

ხუთი წესი, რომელიც თან უნდა წაიღოთ

1უპირატესობა სუფთა ფუნქციებს მიეცით. ერთი და იგივე შესატანი — ერთი და იგივე შედეგი, გვერდითი ეფექტების გარეშე; ეფექტები კიდეებში გაწიეთ.
2ნუ შეცვლით — ჩაანაცვლეთ. უცვლელობა საერთო მდგომარეობის ბაგების მთელ კლასს კლავს.
3მიმართეთ map / filter / reduce-ს. თქვით, რა გინდათ; ციკლი კი დაე გაქრეს.
4ააწყვეთ პატარა ნაწილებისგან. პაწაწინა სუფთა ფუნქციები, კარინგი და პაიპები ერთ დიდ პროცედურას სჯობს.
5არარსებობა & ჩავარდნა ცხადი გახადეთ. Option/Result სჯობს null/throw-ს — და შეურიეთ FP და OOP, ტომს ნუ აირჩევთ.
  • მოკლე, ლოკალური for ციკლი ხანდახან უფრო ნათელია, ვიდრე ჭკვიანური სამნაბიჯიანი ჯაჭვი — წაკითხვადობა იმარჯვებს.
  • ჭარბმა კარინგმა და point-free სტილმა შეიძლება განზრახვა დაფაროს; გამოიყენეთ მხოლოდ იქ, სადაც ის ნამდვილად აზუსტებს.
  • ღრმა რეკურსია დიდ შესატან მონაცემებზე JS-ის სტეკს გადაავსებს — მის ნაცვლად ციკლი ან აკუმულატორი გამოიყენეთ.
  • წარმადობისთვის კრიტიკულ ცხელ გზებს შეიძლება კონტროლირებადი, ლოკალური მუტაცია დასჭირდეს — შემოსაზღვრული და კარგად დასახელებული შეინარჩუნეთ.
ცოდნის შემოწმება

დაგამახსოვრდათ?

ხუთი სწრაფი კითხვა სისუფთავეზე, უცვლელობაზე, მაღალი რიგის ფუნქციებზე, closure-ებსა და Option/Result-ზე — მყისიერი პასუხი, ავტორიზაციის გარეშე.

შეაფასეთ ეს დასტა
იყავით პირველი

ნავიგაცია ← → ღილაკებით ან სქროლით · უკან ბიბლიოთეკაში