Jegyzet
Bár meglepő lehet, de a függvényekkel legelőször már az általános iskola 1. osztályában
találkozunk. Persze, akkor még nem sokkolnak minket ezzel az elnevezéssel, inkább hívják
pl. gépnek, mint ahogyan ez az alábbi tankönyvmásolaton is tetten érhető:
Az ábra alapján a kicsik is hamar kitalálják, hogy a gép a bedobott számból elvesz kettőt,
és a maradékot adja vissza. Ez alapján pedig megfogalmazzák a számolás szabályát, mely
szerint:
=-2
Később, felső tagozatban ugyanezt a "gép"-et már a függvényábrázolás váltja fel. Ekkorra
matematika órán az oldalsó képhez hasonló grafikont kell rajzolgatnunk, és a koordináta-rendszer
tengelyeinek elnevezése alapján az
y=x-2
képlettel kell rá hivatkoznunk. A képlet aztán középiskolában tovább csúnyul, mert ott már az
f(x)=x-2
formációval kell barátkoznunk. Ez az írásmód tartalmában annyival jelent több információt, hogy a
függvénynek lett egy neve, az
f , és hangsúlyosabban jelöljük
benne az
x-et, mint
független változót, amit más
szóhasználattal gyakran hívunk
bemenő adatnak,
paraméternek,
operandusnak, vagy éppen
argumentumnak. Ezek a szavak mind ugyanazt
jelentik.
Matematikából a programozásba
Amikor elkezdünk programozást tanulni, szintén előkerülnek a függvények (már nem is kizárólag
csak matematikai tartalommal, de kétségtelenül ez a lehetőség is bennük rejlik). Azonban új,
de fontos elvárás lesz a programozásnál, hogy minden
függvény neve beszédes legyen,
ami azt jelenti, hogy a választott név utaljon a függvény által végrehajtott műveletre. Így
használhatjuk a fenti matematikai
f(x) helyett a
minuszketto(x)
elnevezést. Ennek a függvénynek a működése tehát például az alábbi konkrét számokkal mutatható be:
minuszketto(5)=3
Példánkban a függvény önkényesen választott neve
minuszketto, a zárójelben szereplő érték a
függvény bemenete, amivel a függvény a műveletet végzi, az egyenlőségjel után található szám pedig
a függvény
eredménye, másként fogalmazva a függvény
visszatérési értéke.
Első osztályos szóhasználattal élve ezt adja eredményül a gép.
Programozáskor a függvény működését annak algoritmusa határozza meg. A
minuszketto() függvény
algoritmusa az alábbiak szerint írható le:
Függvény minuszketto(x)
{
y = x - 2
Visszatérési érték : y
}
Ez alapján természetesen különböző programozási nyelveken is elkészíthető (vagyis definiálható)
a függvény, JavaScriptben például így:
function minuszketto(x)
{
y = x - 2
return y
}
Működése alapján minden függvényhez tartozik egy úgynevezett deklaráció is, mely ahhoz ad leírást,
hogy az adott függvényt hogyan kell használni. (Tehát míg a
definíció a függvény
működését határozza meg, addig a
deklaráció a felhasználáshoz nyújt információt.)
Fenti egyszerű függvényünk deklarációja (leírása) így nézhet ki:
szám minuszketto(szám x)
vagy más írásmóddal ugyenez:
minuszketto(szám x) : szám
ahol mindkét esetben a világoskék színnel írt
szám megjelölés a bemeneti
x változó
típusát jelöli - tehát azt, hogy a függvény egy számot vár paraméterként -, a zöld színnel jelölt
szám kifejezés pedig a függvény visszatérési értékének típusára utal - tehát a függvény
egy számot ad eredményül.
Ezt az írásmódot ismerni, és értelmezni tudni azért fontos, mert a legtöbb programozási nyelv leírása
pontosan ugyanezt a szintakszist alkalmazza függvényeinek bemutatására. Tekintsünk erre két konkrét példát
a négyzetgyökvonás - angolul
square roots - esetén keresztül. E művelet általában a programozási nyelvekben
sqrt néven
valósul meg. A műveletnek nyilvánvalóan egy, azaz 1 darab szám a bemenete - ez az a szám, amiből
négyzetgyököt szeretnénk vonni -, és szintén egy szám a függvény eredménye is - értelemszerűen a
bemenő paraméter négyzetgyöke. A két példa tehát:
Megfigyelhető módon a C# leírás ekként mutatja be a függvényt:
public static double Sqrt (double d);
míg a PHP ismertető így szerepelteti a saját változatát:
sqrt ( float $num ) : float
Eltekintve az adott nyelvek típusainak elnevezéseitől látható, hogy az írásmód pontosan ugyanaz, mint amit
fentebb a saját egyszerű kis
minuszketto függvényünk kapcsán "eljátszottunk". Megszínezve a C#
illetve a PHP leírások sorait ez teljesen egyérteművé is válhat:
public static double Sqrt (double d);
illetve
sqrt ( float $num ) : float
Kétoperandusú függvények
A fentiekben kizárólag olyan függvénnyel foglalkoztunk, amikor a függvénynek pontosan 1 darab bemenete,
vagyis operandusa van. Ezek az egyoperandusú függvények. Ám semmi akadálya annak, hogy egy függvénynek
pl. 2 darab bemenő paramétere legyen. Tipikusan ilyen a
hatványfüggvény, ahol kiinduló adatként
meg kell adni a hatvány
alapját, és a
kitevő értékét, hogy megkaphassuk az eredményt.
28 = 256
ak = ?
Ennek a műveletnek a fügvénydeklarációja így nézhet ki:
hatvany(szám a, szám k) : szám
vagy ahogyan a
C#
és a
PHP ismertetők szerepeltetik
public static double Pow (double x, double y);
illetve
pow ( int|float $base , int|float $exp ) : int|float
Miért nem JavaScript függvényekkel példálózunk?
Azért, mert a JavaScript nyelv hivatalos ismerető oldala, a
w3schools.com
sokkal kevésbé precízen adja meg a függvények deklarációit, mint a C#, vagy a PHP. A hatványozás
függvényéről például
csupán ennyit mond
deklarációként:
Math.pow(x, y)
melyből formálisan nem derül ki sem a bemenő paraméterek típusa, sem pedig a függvény visszatérési értékének
típusa.
Függvények még több operandussal
Persze, ha egy függvénynek nem csak egy, hanem két bemenő paramétere is lehet, akkor ez nyilván tovább
fokozható. E tekintetben az egyik legszebb példát a PHP egyik képmanipuláló függvénye jelentheti, mely
egy képrészletet tud áthelyezni egy másik kép meghatározott pozíciójába. Már e megfogalmazás is sejtetni
engedi, hogy ez igencsak sok paraméter alkalmazását teszi szükségessé, méghozzá szám szerint 10-et! A
PHP ismertetője ezt ekképp tálalja:
imagecopyresampled ( resource $dst_image , resource $src_image ,
int $dst_x , int $dst_y , int $src_x , int $src_y ,
int $dst_w , int $dst_h , int $src_w , int $src_h ) : bool
Az első nekifutásra borzasztó látványból némi tanulmányozás után az derül ki, hogy a függvény
első paramétere a célkép, amire dolgozunk, a második a kiinduló kép, amiről másolunk, a
folytatásban pedig 8 darab szám következik, ami a másolandó képrészlet eredeti és új helyének
kijelölését adja meg az alábbi ábrának megfelelően:
A függvény visszatérési értéke egy logikai érték (igaz, vagy hamis), ami azt mutatja meg, hogy
sikerült-e teljesíteni az adott paraméterekkel megvalósítani kívánt műveletet, vagy sem.
Meglehetősen gyakori dolog a programozási nyelvek esetén, hogy egy-egy függvénytől a logikai
értékként kapott eredményt a művelet sikerességeként kell értelmezni.
Ezen írás célja nyilvánvalóan nem az, hogy a PHP képmásoló módszerét ismertesse,
hanem hogy érzékeltesse: nem életszerűtlen az, amikor egy függvény meglehetősen
sok bemenő paraméterrel operál. A képmásolás lehetőségeivel a
Képmásolás
című oldal foglalkozik.
Függvények bemenő paraméter nélkül
A másik szélsőséget a bemenő paraméterek számában az operandus néklüli függvények jelentik. Adódhat
a kérdés, miből dolgozik egy függvény, aminek egyáltalán nincs bemenő adata. Jellemző válaszként
- immáron akár JavaScriptben is - leginkább a
véletlenszámot előállító függvényt
említhetjük, melynek az a feladata, hogy a "semmiből" állítson elő egy véletlen számot:
Math.random()
Eredményként egy 0 és 1 közötti törtszámot ad a függvény, például ezt:
Természetesen az ilyen számok megfelelő matematikai átalakításokkal tetszőlegesen
továbbalakíthatóak egész értékű, vagy a kívánt pontosságú tört értékű véletlenszámmá
(lásd picivel lentebb, a függvények egymásba ágyazásánal).
Nézzünk két PHP-beli példát is. PHP-ban a matematikai
π
értékét a
pi()
függvény adja meg. Deklarációja szerint
pi() : float
a függvényhez tartozó zárójel üres - vagyis nincs a függvénynek bemenete.
pi() = 3.1415926535898
Egy másik PHP függvény azt tudja megmondani, hogy hány másodperc telt el egy kezdő bázisidőpont óta.
Ez a kezdő bázisidőpont a PHP esetén a 1970. január 1. 00:00:00 - a függvény pedig a
time() .
Deklarációja
time() : int
pillanatnyi értéke pedig
time() = 1725822104
Függvények egymásba ágyazása
Mint ahogyan a matematikában, úgy a programozásban is van lehetőség a függvények egymásba ágyazására,
vagyis arra, hogy egy függvény eredménye egy másik függvénynek a bemenete legyen. Kiváló minta lehet
erre, amikor egy szimuláció során pl. egy lottószámot szeretnénk véletlenszerűen előállítani. Ilyenkor
ugyanis bár használnunk kell a véletlenszámgeneráló függvényt, ez önmagában kevés, mert 1-nél nagyobb
számra, és nem törtszámra van szükségünk, ám a
Math.random() csak ennyit tud. Ám ha ehhez
hozzávesszük a törtszámok egész részét megadni képes
Math.floor() függvényt, akkor már jó
helyzetben vagyunk, hiszen az alábbi formáció produkálja a lottószámot:
Math.floor( Math.random() *90) +1
ugyanis itt a 0 és 1 közti törtszámot megszoroztuk 90-nel, majd ennek vettük az egészrészét. Mivel így
még csak egy 0 és 89 közti egész számot kaptunk, ezért ehhez a kifejezéshez még hozzáadtunk 1-et.
A
lottószám-generálás tehát "működés közben" valahogy így fest:
De mire jó mindez?
A véletlen számok szerepének jelentőségére, alkalmazásuk lehetőségére a
Random
című feladatban találhatóak további változatos példák.
A nem kötelező paraméter
Eddigiek alapján olybá tűnhet, mintha tehát egy függvénynek nagyon határozottan jellemzője lenne,
hogy hány paraméteres, vagyis hogy hány bemenő adata lehet. Ez így is van, ám a paraméterek között
előfordulhatnak olyanok, amiknek a megadása nem kötelező. Általában akkor hagyható el egy paraméter,
ha annak van alapértelmezett értéke, vagyis ha megadás nélkül is behelyettesítődik a helyére valami
konkrét adat. Ez a matematikában nem jellemző lehetőség, ám a programozás során gyakran egyszerűsíti
a munkánkat.
Tekintsük például a PHP azon függvényét, mely
számok kerekítésére szolgál,
és egyszerűsítve így írható a deklarációja:
round ( float $val [, int $precision = 0 ] ) : float
Ebben a felírásban a szögletes zárójel nem része a függvénynek, hanem "csupán" annak jelölésére
szolgál, hogy a közte lévő tartalom nem kötelező. Vagyis a
round függvénynek van 1 kötelező
paramétere - itt adjuk meg, mely számot szeretnénk kerekíteni -, ám adható egy második paraméter is,
mellyel megmondható, hogy hány tizedes számra kerekítsünk. Ennek hiányában a kerekítés egész számra
fog történni, vagyis 0 tizedes pontossággal.
round( 6.52 ) = 7
round( pi() ) = 3
round( pi() , 2 ) = 3.14
round( pi() , 4 ) = 3.1416