Funkcionális programozás Python

Bár a felhasználók általában gondolnak Python mint eljárási és az objektum-orientált nyelv, mindent tartalmaz, amire szükség van, hogy támogassa egy teljesen funkcionális szemléletű programozás.
Ez a cikk ismerteti az általános fogalmak a funkcionális programozás és bemutatja, hogyan kell végrehajtani a funkcionális megközelítés Python.

Mi Python?


Python - egy szabadon elérhető, magas szintű értelmezett nyelv által kifejlesztett Guido van Rossum (Guido van Rossum). Egyesíti a világos szintaxis erős (de nem kötelező) objektumorientált szemantika. Python elérhető szinte az összes létező platformon, és van egy nagyon magas hordozhatóság platformok között.

Mi funkcionális programozás?


Ez a legjobb kezdeni egy nehéz kérdés - de mi, pontosan, egy „funkcionális programozás (FP)”? Az egyik lehetséges válasz - „ez, amikor írsz egy nyelv, mint a Lisp, Scheme, Haskell, ML, ocaml, tiszta, Mercury vagy Erlang (vagy akár más).” Ez a válasz, persze, ez igaz, de nem sok tisztázza a lényeg. Sajnos, hogy tiszta képet, amit az FP, nagyon nehéz, még a saját funkcionális programozók. Emlékszem a példázat a három vakok és az elefánt. Lehetőség van arra is, hogy meghatározzák a FP, kontrasztos ő „imperatív programozási” (mit csinál a nyelvek, mint a C, Pascal, C ++, Java, Perl, awk, TCL, és még sok más - legalábbis a legtöbb).

* Funkciók - első osztályú objektumokat. Ie minden, amit tehetünk „adat”, lehet tenni a funkciók (például az átviteli függvényt egy másik függvény paraméterként).
* Használata rekurzió mint a fő vezérlő áramlásszabályozó szerkezetet. Egyes nyelvek, van egy másik tervezési ciklusban, kivéve a rekurziót.
* Fókuszban a feldolgozási lista (listák, innen a név a Lisp --lista). List rekurzív allistákra gyakran használják a csere ciklus.
* A „tiszta” funkcionális nyelvek mellékhatások elkerülése. Ez kizárja csaknem mindenütt jelen elengedhetetlen nyelven megközelítést, amely ugyanazt a változót egymást rendelt különböző értékeket az állami nyomkövető program.
* FP nem hagyja jóvá, vagy teljesen megtiltják nyilatkozatok (nyilatkozatok) alkalmazásával helyett az értékelési kifejezések (azaz funkciók érveket). Szélsőséges esetben, egy program egy expressziós (plusz kiegészítő meghatározásokat).
* FP összpontosít, hogy mit kell kiszámítani, és nem, hogy hogyan.
* A legtöbb FP függvény „magasabb rendű” (funkciók működési funkciók működési funkciók).

Védők funkcionális programozás azt állítják, hogy mindezek a jellegzetességek vezet gyorsabb fejlődés a rövidebb és hibamentes kódot. Sőt, a nagy teoretikusai számítástechnika, a logika és a matematika a megállapítás, hogy a folyamat igazoló hivatalos tulajdonságai funkcionális nyelvek és a programok sokkal könnyebb, mint kötelező.

Funkcionalitás rejlő Python


Python támogatja a legtöbb jellemzője a funkcionális programozás, mivel verzió Python 1.0. De mint a legtöbb Python funkciók vannak jelen nagyon vegyes nyelven. Csakúgy, mint az objektum-orientált Python funkciókat használhatja, amire szüksége van, és figyelmen kívül hagyja a többi (mindaddig, amíg szükség van rá később). A Python 2.0 adunk nagyon jó „szintaktikus cukor” - lista comprehensions (lista comprehensions). Bár nem hozzátéve alapvetően új lehetőségeket, lista comprehensions igénybe sok a régi funkciók sokkal szebb.

Az alapvető elemei FP Pythonban - térképen () funkció, csökkenti a (), szűrő (), és a kezelő lambda. A Pythonban 1.x bevezetett is alkalmazni () függvény egy kényelmi funkció közvetlen alkalmazását a visszaadott lista a többi. Python 2.0 tárgya javított szintaxisa. Kissé váratlanul, de ezeket a funkciókat, és csak néhány alapvető szereplők közel ahhoz, hogy írni minden program Python; különösen a vezérlő utasítások ( „ha”, „elif”, „más”, „érvényesíteni”, „próbálja meg”, „kivéve”, „végre”, „az”, „szünet”, „folytatás”, „míg a” „def”) is képviselteti magát a funkcionális stílusú, kizárólag a függvények és operátorok. Annak ellenére, hogy az igazi probléma az eltávolítása az összes vezérlési parancsok csak akkor hasznos előadás a verseny „érthetetlen Python” (kóddal, hogy néz ki a Lisp program), érdemes megérteni, hogyan FP fejezi irányító struktúrákat funkciót hívások és rekurziót.

Kivétel áramlás vezérlő parancsok


Az első dolog, érdemes megjegyezni a gyakorlat -, hogy a Python „rövidzárlat” számítási logika vyrazheniy.1 kiderül, hogy ez biztosítja egyenértékű egység „ha” / „elif” / „else” a kifejezési forma. Tehát:

------ „zárlatos” feltételes hívások Python ----- #
# Szokásos ellenőrzési struktúrák
ha : Func1 ()
elif : Func2 ()
más: func3 ()

# Ekvivalens „rövidre zárja” kifejezést
( és func1 ()) vagy ( és func2 ()) vagy (func3 ())

# Példa a „rövidre záródik” expressziós
>>> X = 3
>>> def pr (ek): hozam s
>>> (x == 1 és PR ( 'egy')) vagy (x == 2 és PR ( 'két')) vagy a (pr ( 'egyéb'))
Az „egyéb”
>>> X = 2
>>> (x == 1 és PR ( 'egy')) vagy (x == 2 és PR ( 'két')) vagy a (pr ( 'egyéb'))
„Két”


Úgy tűnik, hogy a mi változata feltételes hívásokat kifejezések - nem több, mint egy szalon hangsúly; Azonban a dolgok sokkal érdekesebb, ha figyelembe vesszük, hogy az üzemeltető lambda kifejezés tartalmazhat csak! Mint ahogy azt az imént bemutatott kifejezéseket is tartalmazhat feltételes blokkon, egy rövidzárlat, a lambda kifejezés lehetővé teszi általánosságban bevezetni feltételes visszatérési értékeket. Ennek alapján az előző példában:

# --------- Lambda rövidzárvédelemmel feltételes kifejezések Python ------- #
>>> pr = lambda s. s
>>> namenum = lambda x. (X == 1 és PR ( "egy"))
. vagy (x == 2 és PR ( "két"))
. vagy (pr ( "egyéb"))
>>> namenum (1)
„Egy”
>>> namenum (2)
„Két”
>>> namenum (3)
Az „egyéb”

Funkciók, mint az első osztályú objektumok


Ezek a példák már tanúi, bár nem egyértelmű, hogy a jogosult funkciók, mint az első osztályú objektumok Python. A tény az, hogy hozzon létre egy függvény objektum üzemeltető lambda, tettünk egy nagyon gyakori művelet. Tudtunk kötni a tárgy nevét és pr namenum pontosan ugyanúgy, ahogy tudta kötni a 23-as szám vagy „spam” sort ezeket a neveket. De mint a 23-as szám nélkül lehet használni azért, hogy olyan nevet (például érvként, hogy a függvény), akkor használja ezt a funkciót által létrehozott objektum lambda, nem azért, hogy bármilyen nevet. Funkció Python - csak egy másik érték, amivel lehet valamit csinálni.

A legfontosabb dolog, hogy mi köze van az első osztályú objektumok - át őket a beépített funkciókat térkép (), csökkenti a () és a szűrő (). Ezeket a funkciókat vesz egy tárgyat, mint az első érv. térkép () az átadott függvényt minden egyes eleme a bemeneti lista (listák), majd visszaadja az eredményt. csökkentése () használja az átadott funkció minden egyes érték a listán, és vezetni a belső eredményt; például csökkenti a (lambda N, m: n * m, tartomány (1,10)) 10! (Factorial 10 - szaporodnak minden eleme az eredmény az előző szorzás). Keresés () az átadott függvényt minden egyes elemet a listából, majd visszaadja az elemek az eredeti listán, amelyet továbbított a függvény TRUE értékkel tér vissza. Azt is gyakran hoznak funkció tárgyakat a saját funkciója, de gyakran valamilyen kombinációja a fenti beépített funkciókat.

Ezek egyesítésével három FP beépített funkció, akkor végre sokféle váratlan control flow műveleteket anélkül, hogy nyilatkozatok (nyilatkozatok), és csak ezt a kifejezést.

Funkcionális ciklusok Python


Csere ciklus kifejezést olyan egyszerű, mint helyettesíti a feltételes blokkokat. „A” közvetlenül átvihetjük a térkép (). Csakúgy, mint a feltételes végrehajtását, meg kell, hogy egyszerűsítse a blokk nyilatkozatok egyetlen függvényhívás (közel vagyunk, hogy tanulni, hogy csináld általános esetben):

# ---------- funkcionális 'for' ciklus a Python ---------- #
e az lst. funk (e) # jóváhagyás 'for' ciklus
térkép (funk. lst) # ciklust, amely a térképen ()


Mellesleg, egy hasonló technikát alkalmaznak végrehajtásához következetes végrehajtása a program segítségével egy funkcionális megközelítés. Ie imperatív programozási többnyire áll nyilatkozatok, hogy kell „csinálni, akkor csináld, akkor valami mást.” „Map ()” lehetővé teszi, hogy fejezhető ki:

# ----- Funkcionális következetes végrehajtása Python ---------- #
# Létrehozása segítő funkciót hívás funkció
do_it = lambda f. F ()

# Legyen f1, f2, f3 (stb.) - funkciók elvégzésére alkalmas intézkedések
térkép (do_it. [f1. f2. f3]) # szekvenciális végrehajtást végrehajtani a térképen ()


Általában minden a fő program lehet egy kihívás „map ()” egy listát a funkció csak következetesen okoz a program futtatására. Egy másik hasznos tulajdonsága funkcionál tárgyak -, hogy akkor őket a listán.

Fordítás „míg a” közvetlenül egy kicsit nehezebb, de kiderül:

# -------- funkcionális 'while' ciklus Python ---------- #
# Neutral (alapján jóváhagyásra a „while”) ciklus
míg :


ha :
szünet
más:

# A rekurzív hurok a funkcionális stílusban
def while_block ():


ha :
return 1
más:

return 0

while_FP = lambda. ( és while_block ()) vagy while_FP ()
while_FP ()


A változata „míg a” mindig szükség while_block () függvény, amely maga is tartalmazhat nemcsak a kifejezés, hanem nyilatkozatok (utasítások). De lehetne folytatni tovább kivétel a nyilatkozatok a funkciót (például a csere blokk „if / else” a fenti sablont, a zárlatos kifejezés). Ezen túlmenően, egy rutinellenőrzés a helyszínen (Mint például a „while myvar == 7”) nem valószínű, hogy hasznos lehet, mert a szervezet a hurok (ahogy) nem tudja megváltoztatni a változók (bár a globális változók lehet változtatni while_block ()). Az egyik mód arra, hogy több hasznos állapot - teszi while_block () visszatér egy értelmes értéket, és hasonlítsa össze a feltétellel befejezését. Vessen egy pillantást a valós példáját nyilatkozatok kivételekkel:

# ---------- működési ciklust 'echo' Python ------------ #
Felszólító # változata "echo ()"
def echo_IMP ():
míg 1:
X = raw_input ( "IMP -")
ha x == 'quit':
szünet
más
print x
echo_IMP ()

# A hasznossági függvény, amely megvalósítja „azonosságot mellékhatások”
def monadic_print (x):
print x
visszaút x

# FP változata "echo ()"
echo_FP = lambda. monadic_print (raw_input ( "FP -")) == 'quit' vagy echo_FP ()
echo_FP ()


Elértük, hogy kifejezte a kis program, beleértve az I / O ciklus és feltételek, mint egy tiszta kifejezést rekurzió (sőt - mint funkcionális tárgy, amely bárhol át lehet, ha szükséges). Még mindig használja monadic_print () hasznossági függvény, de ez a funkció elég gyakori, és fel lehet használni a funkcionális szempontból. hogy fogunk létrehozni később (ez egyszeri költség) 0,2 3 Figyeljük meg, hogy minden olyan kifejezést tartalmazó számított ugyanúgy, mintha benne csak x monadic_print (x). Az FP (különösen a Haskell) van fogalmát „monád” egy funkció, hogy „nem csinál semmit, és súlyos mellékhatásokat okozhat a teljesítmény.”

Kizárása mellékhatások


Elvégre ez a munka, hogy megszabaduljon a tökéletesen ésszerű struktúrák és helyettük homályos Beágyazott kifejezéseket, természetes kérdés merül fel - „Miért?!”. Olvasás az én leírását FP ​​teljesítmény, azt látjuk, hogy azok minden történt a Python. De a legfontosabb (és a legvalószínűbb, hogy a legnagyobb mértékben reálisan használható) funkció - kizárását a mellékhatásokat, vagy legalábbis korlátozzák a speciális területeken, mint a monád. A nagy százalékban programot hibák és a fő probléma, amely megköveteli a használatát hibakeresőkkel, történetesen annak a ténynek köszönhető, hogy a változók helytelen értékeket a folyamat a program végrehajtásának. Funkcionális programozás körül ezt a problémát, egyszerűen nem tulajdonított érték változók.

Nézd meg a nagyon gyakori helyén elengedhetetlen kódot. Az ő célja - kinyomtatni egy listát a számpárok, amelyek terméke a több mint 25. A számok teszik ki a párokat, maguk vett két másik lista. Mindez nagyon emlékeztet, amit a programozók valójában sok részén a programokat. Kötelező megközelítése ennek a problémának a következőképpen nézhet ki:

# --- Felszólító kódot „nyomdaipari termékek” ---- #
# Eljárási stílus - talál nagy művek felhasználásával ágyazott hurkok
xs = (1. 2. 3. 4.)
ys = (10. 15. 3. 22)
bigmuls = []
#. más kódot.
az x xs:
A y ys:
#. más kódot.
ha x * y> 25:
bigmuls. append ((x. y))
#. más kódot.
#. más kódot.
print bigmuls

A funkcionális megközelítés a probléma teljesen kiküszöböli a hibákat mellékhatásokkal járnak. Egy lehetséges megoldás a következő lehet:

# --- Funkció kódkeresést / nyomtatás nagy művek Python ---- #
bigmuls = lambda xs. ys. szűrő (lambda (X y) :. x * y> 25. kombinálni (xs YS).)
kombinálni = lambda xs. ys. térkép (Semmi. xs * len (év), dupelms (ys. len (xs)))
dupelms = lambda lst. n. csökkentése (lambda s. t. s + t. térkép (lambda L. N = N. [l] * n. LST))
print bigmuls ((1. 2. 3. 4.) (10. 15. 3. 22))


Mi jellemző példa névtelen (lambda), akiknek a neve, de ez nem feltétlenül szükséges. Ehelyett csak fel a meghatározás. Mi használt nevek, mint a könnyebb olvashatóság, és mivel kombinálják () - minden esetben egy nagy hasznossági függvény (generál egy listát az összes lehetséges pár elemek két lista). Az viszont, dupelms () alapvetően csak kiegészítő részt összekapcsolják (). Bár ez a funkcionális például még bővebb, mint a kötelező, az újrahasználat szolgáltatási funkciók a megfelelő kódot bigmuls () lenne talán tömörebb, mint elengedhetetlen megtestesítője.

Az igazi előnye ennek funkcionális például az, hogy egyáltalán nincs változó nem változik az értéke. Bármilyen nem várt mellékhatásokkal később kód (vagy az előző kód) egyszerűen lehetetlen. Természetesen a puszta mellékhatások nélkül nem garantálja a hibamentes kódot, de minden esetben ez előnyt jelent. Fontos megjegyezni ugyanakkor, hogy a Python, ellentétben sok funkcionális nyelvek, nem akadályozza meg az újra árukapcsolás nevek bigmuls, kombinálni és dupelms. Ha továbbra is a folyamat végrehajtása kombinálni () program elkezd jelent mást - sajnos! Lehetséges lenne, hogy dolgozzon ki egy osztályt-alone (Singleton) támogatni egyetlen kötési ilyen típusú (pl. „S.bigmuls”, stb), de ez túlmutat ezt a cikket.

Tovább érdemes megjegyezni, hogy a feladat, amit most úgy döntött, hogy pontosan szabott az új Python 2.0 funkciókat. Ahelyett, hogy a fenti példák - kényszerítő vagy funkcionális - a legjobb (és funkcionális) technika a következő:

# ----- Python kódot "bigmuls" -ta listából comprehensions (lista comprehensions) ----- #
nyomtatás [(x. y) x (1. 2. 3. 4.) az y (10. 15. 3. 22), ha x * y> 25]

következtetés

Kapcsolódó cikkek