Ֆունկցիոնալ ծրագրավորում Python-ով

Ծրագրավորման լեզուներ

Marina Vardanyan
Picsart Academy
4 min readMay 18, 2022

--

Մինչ Python-ով իրականացվող ֆունկցիոնալ ծրագրավորմանն անդրադառնալը, սահմանենք, թե ինչ է ֆունկցիոնալ ծրագրավորումն ընդհանրապես։

Ֆունկցիոնալ ծրագրավորումը ծրագրավորման մի մոդել է, որում հաշվարկման պրոցեսը մեկնաբանվում է որպես ֆունկցիայի արժեքների հաշվարկ՝ վերջինիս մաթեմատիկական հասկացությամբ:

Ֆունկցիոնալ ծրագրավորման հիմնական հատկությունը կողմնակի ազդեցությունների (side effects) բացակայությունն է։ Ի տարբերություն ծրագրավորման այլ մոդելների, որտեղ միևնույն արգումենտներով, բայց ալգորիթմի տարբեր էտապներում աշխատող միևնույն ֆունկցիան կարող է վերադարձնել տարբեր տվյալներ՝ փոփոխականների վիճակի (state) վրա ֆունկցիայի ազդեցության պատճառով, ֆունկցիոնալ ծրագրավորման դեպքում միևնույն արգումենտներով ֆունկցիայի կանչի ժամանակ միշտ կստանանք նույն արդյունքը, քանի որ ելքային տվյալները կախված են միայն մուտքային տվյալներից:

Կողմնակի ազդեցությունների (side effects) բացակայությունը և նույն մուտքային տվյալների դեպքում նույն ելքային տվյալների ստացումը մաքուր ֆունկցիաների հատկություններն են։ Մաքուր ֆունկցիայի արդյունքը կարող է քեշավորվել, այսինքն` արգումենտի հետ միասին պահվել ինչ-որ աղյուսակում, որից հետո, այդ արգումենտով կանչի դեպքում, ոչ թե ամեն անգամ հաշվարկվի արժեքը, այլ օգտագործվի աղյուսակում եղածը, քանի որ այդ արժեքը միևնույն արգումենտի դեպքում միշտ նույնն է լինելու։ Այդպես, ավել հիշողություն օգտագործելով, կարելի է արագացնել ծրագրի աշխատանքը՝ նվազեցնելով ֆունկցիայի կանչերի քանակը։

Բացի այդ, մաքուր ֆունկցիաները կարող են կատարվել ցանկացած հերթականությամբ կամ նույնիսկ միաժամանակ, եթե նրանց միջև չկա կախվածություն, քանի որ դրանք չեն փոխում արտաքին տվյալները։

Ֆունկցիոնալ և ոչ ֆունկցիոնալ կոդի տարբերությունն ավելի հասկանալի դարձնելու համար, դիտարկենք երկու տարբեր կոդի օրինակներ, որոնցից մեկը գրված է ֆունկցիոնալ ծրագրավորման սկզբունքով, իսկ մյուսը՝ իմպերատիվ։

Ոչ ֆունկցիոնալ ֆունկցիայի օրինակ.

Ֆունկցիոնալ ֆունկցիայի օրինակ.

Առաջին օրինակում ֆունկցիայից դուրս հայտարարված փոփոխականի արժեքը փոփոխվում է ֆունկցիայի ներսում, իսկ երկրորդ օրինակում՝ ֆունկցիան պարզապես վերադարձնում է հաշվարկի արդյունքը։

Python-ն ունի հարուստ և հզոր գործիքներ, որոնք հեշտացնում են ֆունկցիոնալ ծրագրավորման սկզբունքի վրա հիմնված ծրագրերի մշակումը: Այդպիսի միջոցներից են ցուցակների ներառումները (list comprehension) կամ, այսպես կոչված, ցուցակների աբստրակցիաները (list abstraction), լյամբդա կամ անանուն ֆունկցիաները (lambda functions), բարձր կարգի ֆունկցիաները(higher order):

Օրինակ, [1,1000) միջակայքի բոլոր զույգ թվերը ստանալու համար, ցուցակների ներառումները (list comprehension) օգտագործելով, կարելի է գրել․

Կամ, եթե ունենք ինչ-որ ցուցակ(list), ապա այդ ցուցակի բոլոր տարրերի քառակուսիները կարելի է ստանալ հետևյալ կերպ․

Կարելի է ներառումները (list comprehension) օգտագործել նաև բազմությունների (set) և բառարանների (dict) համար։
Բազմության դեպքում փոխվում է օգտագործվող փակագիծը՝ {}-ը []-ի փոխարեն, և ստացված արդյունքը պարունակում է միայն եզակի տարրեր, ինչն էլ հենց բազմության հատկությունն է։
Օրինակ՝ {x for x in [1, 2, 2, 2, 3, 1]} գործողության արդյունքը {1, 2, 3} եզակի տարրերով բազմությունն է։ Բառարանների դեպքում պետք է օգտագործվի key:value զույգը։
Օրինակ՝ mydictբառարանի key:value զույգի արժեքների տեղերը փոխել կարելի է հետևյալ կերպ․

Եթե ենթադրենք, որ բերված օրինակում mydict = {'1': 'val1', '2': 'val2'}, ապա փոփոխված բառարանը կլինի՝ rev_key_val = {'val1': '1', 'val2': '2'}:

Լյամբդա ֆունկցիաները փոքր ֆունկցիաներ են, որոնք կարող են ընդունել ցանկացած քանակությամբ արգումենտ, բայց մարմինը կարող է պարունակել ընդամենը մեկ արտահայտություն։

Լյամբդա ֆունկցիաներն ունեն հետևյալ տեսքը․

2 թվի արտադրյալ հաշվելու համար կարելի է գրել հետևյալ տեսքն ունեցող լյամբդա ֆունկցիան և վերագրել այն փոփոխականի․

Ապա կանչել այդ ֆունկցիան հետևյալ կերպ․

կամ՝ առանց անվանակոչման, ինչպես այստեղ է.

Ինչպես տեսնում ենք բերված օրինակում, լյամբդա ֆունկցիաները, ի տարբերություն սովորական ֆունկցիաների, կարելի է կիրառել անմիջապես հայտարարելուց հետո։
Լյամբդա ֆունկցիաները ծրագրի գործարկման ժամանակ իրականացվող ֆունկցիաներ են (run-time functions):
Դրանք հաճախ են օգտագործվում Python-ի այնպիսի ֆունկցիոնալ գործիքներում, ինչպիսիք են օրինակ map(), filter() բարձր կարգի ֆունկցիաները (higher order)։

Բարձր կարգի ֆունկցիաներ են կոչվում որպես արգումենտ ֆունկցիա ստացող կամ մեկ այլ ֆունկցիա վերադարձնող ֆունկցիաները։

Ստորև բերված օրինակում g()-ն բարձր կարգի ֆունկցիա է․

map() ֆունկցիան ունի հետևյալ տեսքը՝ map (ֆունկցիա, հաջորդականություն), filter() ֆունկցիան, ևս, ունի նույն տեսքը։
map()-ը օգտագործվում է հաջորդականության բոլոր տարրերի համար տրված ֆունկցիան կիրառելու, իսկ filter()-ը՝ հաջորդականությունից ֆունկցիայի հիման վրա արժեքները ֆիլտրելու համար։
Ստորև բերված են map() և filter() ֆունկցիաներում լյամբդա ֆունկցիայի օգտագործման օրինակներ (նշումներում բերված է արդյունքը)։

Ռեկուրսիան նույնպես ֆունկցիոնալ ծրագրավորման գործիք է: Ռեկուրսիվ ֆունկցիայի դասական օրինակ է ֆակտորիալ հաշվող ֆունկցիան՝

Եվ այսպես, ֆունկցիոնալ ծրագրավորման ուշադրության կենտրոնում ֆունկցիաներն են, որոնք կարող են վերագրվել փոփոխականների, կարող են փոխանցվել այլ ֆունկցիաների որպես արգումենտ և կարող են ստեղծել նոր ֆունկցիաներ։

--

--