A Dylan programozási nyelv

Függvények



Függvények

A Dylan nyelvben minden művelet egy függvény. A függvényeknek nulla vagy több argumentumuk és nulla vagy több visszatérési értékük van. A függvény paraméterlistája megadja a paraméterek és a visszatérési értékek számát és típusát.
A függvényeknek két csoportja van, a metódus (method) és a generikus függvény (generic function). Mindegyiket ugyanúgy használjuk, a függvény hívójának nem is kell tudnia, hogy metódust vagy generikus függvényt hívott. A metódus a futtatható kód egy egysége. A metódus fogadhat paramétereket, amelyekhez lokális neveket rendel. Lefuttatja a törzset ezeknek a lokális neveknek a terében és visszatérhet valamilyen értékekkel.
A generikus függvény metódusokat foglal magába. Amikor egy generikus függvényt meghívunk összehasonlítja az argumentumait azoknak a metódusoknak a paraméterlistáival, amelyeket tartalmaz. A paraméterlista alapján kiválasztja a megfelelő metódust és átadja neki az argumentumokat. A generikus függvény a polimorfizmust megvalósító eszköz a Dylan nyelvben.
A Dylanban minden függvény objektum, méghozzá a funcion példánya. Ezen kívül a metódusok példányai a method-nak, a generikus függvények pedig a generic-function-nak.

Generikus függvények

Generikus függvényeket kétféleképp hozhatunk létre: a define generic segítségével, vagy pedig a make utasítás használatával. A make utasítás segítségével hozhatjuk létre egy típus egy példányát, tehát a második esetben a make utasítást a típusra kell meghívni.
A define generic haszbálata azonban jóval gyakoribb.
Ha egy osztályhoz adattagot definiálunk (lásd Objektum orientált programozás) akkor létrejönnek az adattagot beállító és lekérdezo generikus függvények.

A következő példában definiálunk egy generikus függvényt amelynek egy paramétere van.

define generic double()

Ehhez a generikus függvényhez olyan metódusokat adhatunk, amelyeknek egy (kötelező) paraméterük van. A következő példában definiálunk egy olyan generikus függvényt, amelynek két number típusú paramétere van.

define generic average(n1 :: number, n2 :: number)

Metódusok

Metódusokat definiálására három lehetőség van:


Metódus létrehozása a make utasítással nem lehetséges.
define method

A define method-al létrehozott metódus hozzáadódik a generikus függvényhez. Ha még nem definiáltuk a hozzá tartozó generikus függvényt akkor létrehozza azt. Tehát egy ilyen módon létrehozott metódus vagy létrehoz egy generikus függvényt, vagy hozzáadódik egy már meglévőhöz. Akkor kell a metódusunkat ilyen módon definiálni, ha használni akarjuk a polimorfizmust.

define method double (thing :: number) => nother-thing :: number; thing + thing; end method;

Ez a metódus egy
típusú argumentumot fogad el, és visszatér a duplájával. A metódus hozzáadódik a double nevű generikus függvényhez, amit feljebb definiáltunk.
Itt hívjuk fel a figyelmet a Dylan nyelv következő tulajdonságára: a nyelvben minden egyes blokknak van értéke. Ha nem adunk meg mást, akkor egy blokk értéke a benne szereplő legutolsó kifejezés értéke. Ha definiálunk egy metódust és külön nem adjuk meg a visszatérési értéket, akkor az utolsó kifejezés értékével tér vissza. Tehát a példánkban szereplő metódus a thing + thing
értékével fog visszatérni.

local

A local-al létrehozott metódus neve a blokkon belül lokális lesz. Egy local deklarációval több metódust is létrehozhatunk, ezek a metódusok meg is hívhatják egymást. Az ilyen metódusok rekurziót is tartalmazhatnak.

define method newtons-sqrt (x :: number) local method sqrtl (guess) // meghivunk egyéb lokális metódusokat if (close-enough?(guess))guess else sqrtl (improve (guess)) //rekurzió end if end sqrtl, method close-enough? (guess)abs (guess * guess - x) < .0001 end close-enough?, method improve (guess)(guess + (x / guess )) / 2 end improve; sqrtl(1) end method newtons-sqrt;

A példában a newtons-sqrt metóduson belül (melyet a define method -al hoztunk létre) létrehozunk három lokális metódust. A három metódus egymás után van megadva, vesszővel elválasztva. A három metódus hívhatja egymást vagy akár önmagát is, ahogy azt az sqrtl lokális metódus esetében látjuk.

Ez a három lokális metódus máshonnan nem hívható, csak a newtons-sqrt törzsén belül (mert ott lettek definiálva). Fontos, hogy a fenti példában mindhárom "belső" metódus lokális, de a második és a harmadik estében már nem kellett kiírni a local kulcsszót. (Egy local után több lokális metódust is definiálhatunk).

method

Metódust közvetlenül a method utasítással is létrehozhatunk. Az ilyen metódust eltárolhatjuk egy változóban, és utána felhasználhatjuk függvényparaméterként, vagy eltárolhatjuk egy adatstruktúrában.

define constant square = method (n :: ) n * n; end method;

Gyakran hasznos, hogy létrehozzunk egy metódust, melyet átadunk egy másik metódusnak. Nézzük meg a következő példát:

sort (person-list,test : method(person1, person2)
person1.age < person2.age end method)

A rendező metódusnak átadunk paraméterként egy emberekből álló listát, és egy metódust amellyel megadjuk a rendezés módját. A fenti példában a rendezés a személyek életkora alapján történik.

Visszatérési érték

A Dylan metódusoknak nincsen normál "kimeneti" paramétere megadva a paraméterlistában, így sokkal rugalmasabbak a visszatérési értékekkel. A metódusok akár több értéket is visszaadhatnak. Ahogyan a paraméterek, ezekenk az értékeknek is lehetnek típusosak, vagy típus nélküliek. Minden visszatérési értéknek kell legyen neve.
A Dylan metódusoknak - ahogyan minden vezérlő szerkezetnek is - van értéke, ami az utolsó kifejezés értéke a törzsben.

define method foo() => sample :: string; "Sample string."; // return string end; define method bar() => my-untyped-value; if (weekend-day?(today())) "Let's party!"; // return string else make(excuse); // return object end if; end method; define method moby( ) => sample :: string, my-untyped-value; values( foo(), bar() ); // return both! end; define method baz( ) => ( ); let (x,y) = moby( ); // assign both end;

A blokk utasítások egy csoportja. Mint minden vezérlési szerkezetnek, ennek is van (visszatérési) értéke. Ha erről máshogy nem rendelkezünk, akkor a blokk értéke az utolsó kifejezés értéke:

block () 1 + 1; end; // returns 2
A blokkok támogatják a nem lokális kilépést. Ez lehetővé teszi, hogy a blokk bármikor kiléphessen, és opcionálisan adhat visszatérési értéket. Hogy hassználhassuk ezt a lehetőséget, a blokk kezdetét jelző block kulcsszó után meg kell adnunk egy nevet, amit a Dylan egy kilépési függvényhez köt, amit bárhol meghívhatunk a blokkon belülről, vagy a blokkból hívott függvényekből. A következő példában a blokk egyaránt visszatérhet a "Weird!" vagy a "All's well." string -el, attól függően, hogy milyen színű az ég.

block (finished) if (sky-is-green()) finished("Weird!"); end; "All's well." end block;

Különleges argumentumok

Függvényeknél lehetőségünk van különleges paraméterek megadására. A normál paraméterek száma és sorrendjük rögzített, és megadásus kötelező. A Dylan függvényeknél változhat a további paraméterek száma.

#rest

A #rest paraméter gyűlytemények korlátlan számú argumentumok, mint egy sorozat. Például a következő függvénynek egy kötelező paramétere van (view), és tetszőleges további paraméter adható meg (points). A függvény belsejében egy for ciklus fog végiglépkedni ezeken az opcionális argumentumokon.

define method polygon (view :: point, #rest points) for (p in points) ... end for; end method;

A függvényt pedig az alábbi módokon lehet használni:
polygon(myWindow, p1, p2, p3, p4, p5); // Typical usage

#key

A kulcsszó paramétereket a #key segítségével adhatjuk meg, ami igen hasznos, különösen a sok paraméteres függvényeknél, amelyeknek van alapértelmezett értéke. Ez a lehetőség biztosítja, hogy tetszőleges sorrendben adhatsuk meg a paramétereket, vagy akár el is hagyhassuk a megadását, amennyiben van alapértelmezett érték. Ezáltal növekszik a hívó kód olvashatósága.

define method rent-car (customer :: string, // 2 kötelező paraméter location :: string, // és még 4 opcionális #key color = white:, // Default color is white sunroof? = #f, // Default no sunroof automatic? = #t, // Default automatic shift days = 3) // Default 3-day rental ... end method;

A metódust több módon is hívhatjuk. Kulcsszó argumentum nélkül, vagy akár kulcsszavakkal azonosított paraméterekkel is.

rent-car(arnold, dallas, days: 7, sunroof?: #t); rent-car(betty, dallas, days: 8, color: #"red"); rent-car(colin, vegas); // minden alapértelmezett

A programozónak egy kis szabadsága van a kulcsszó argumentumok specifikálásánál. Tetszőlegesen elhagyhatja az alapértelmezett értékét egy kulcsszónak (ekkor #f lesz). Alapértelmezett érték megadásánál valójában a függvény önmagát hívja, és támaszkodhat a hagyományos paraméterekre, amelyek beléptek a láthatósági mezőbe. A változónevek különbözhetnek a kulcsszó nevektől, ami egy ügyes eszköz a névkonfliktusok megelőzésére.