Az Opal programozási nyelv

Alprogramok, modulok

Függvények deklarációja

A deklarációt a "FUN" kulcsszó vezeti be. Ezt követi a deklarálandó függvény neve, majd a paraméterek felsorolása. A deklaráció utolsó eleme, pedig a függvény visszatérési típusa.

FUN rabbits : nat -> nat
FUN add : nat ** nat -> nat

Létezik viszont olyan függvény amelynek sem paraméterei, sem visszatérési típusa sincs.

FUN main : com

Azt mondják, hogy a "main" nem vesz át semmilyen értéket, azaz a "main" egy konstans a com (command-ok) között.

A nyelv támogatja a párhuzamos értékadást, tehát megengedett függvénydeklaráció a következő:

FUN divmod : nat ** nat -> nat ** nat

De a függvény visszatérési értéke, maximum 16 mezőből állhat, platformtól függően. Ha ennél véletlenül több kellene, akkor új adattípus bevezetését javasolják az Opal készítői.

Lehetőség van egy függvény paraméterként való átadására is, ezt nevezik higher-order függvényeknek.

Például a határozott integrál kiszámítására egy függvény:

FUN integral : (real -> real) ** real ** real -> real

Ismeretes a matematikában, hogy minden egynél több paraméterrel rendelkező függvényre létezik egy transzformáció, amely egy paramétert vár, és egy másik függvény az értéke, (amelynek szintén egy paramétere van), úgy, hogy a szemantika megmarad. Azaz:

FUN add : nat ** nat -> nat
FUN add : nat -> nat -> nat

A fenti átírás létezik, de mind a két függvény ugyanazt jelenti. A legtöbb funkcionális nyelven ez az átírás bele van építve a nyelvbe, és nem kell külön átírni. Az Opal fejlesztői azonban amellett döntöttek, hogy az első eset az infix jelölésmód esetén használható, a második eset a postfix jelölés esetén, és külön kell deklarálni, és definiálni őket. Ezt a módszert a funkcionális nyelvek esetén carrying-nek hívják.

Ez az eljárás optimalizálásra is használható, mivel ha egy add(3) (.)-at lát a fordító, akkor neki egy olyan függvényt kell csak generálni, amelyik a paraméteréhez 3-at hozzáad. Így hatékonyabb lesz a kész program, másrészt, egy már megírt függvény segítségével definiáltuk annak egy speciálisabb esetét, anélkül, hogy a nat struktúra add függvényéről bármit is tudnánk.

Függvények definíciója

A függvények deklarálásánál megadtuk, hogy milyen adatokkal működjenek a függvények, itt a definiálásban kell rögzíteni, hogy miként tegyék ezt.

A definíciót a "DEF" kulcsszó vezeti be, ezt követi a függvény neve, majd kerek zárójelek között a paraméterek felsorolása. Ez a felsorolás már nem tartalmaz típusokat, mivel az már a deklarációnál megtörtént, csak a neveket, amelyeken keresztül az adatokat a függvény törzsében látni lehet. Ezt követi az "==" kulcsszó, majd a függvénytörzs.

DEF rabbits(gen) == <>
DEF integral(f, min, max) == <>

Ahogy az egy ilyen szintű nyelvtől elvárható, támogatja a nevek túlterhelését.

A függvényekre való hivatkozás lehet infix, vagy postfix. Ezért a következő írásmódok egy függvényre való hivatkozás esetén megegyeznek:

DEF !(str, n) == << body >> DEF str ! N == << body >>

Mivel a formulák átírhatók olyan alakra, hogy függvényt kelljen visszaadniuk, ezért akár dinamikusan is dönthet egy függvény arról, hogy mit fog csinálni a változóival.

FUN dyop : dyadicOp -> nat ** nat -> nat
DEF dyop : (op)(l,r) == IF op addop? THEN +(l,r)

Előfordulhat olyan eset, hogy az általunk írt struktúra egy függvénye megegyezik egy már megírt függvénnyel. Ekkor, ha a paraméterek sorrendje megegyezik, akkor a definícióban nem kell kiírni.

FUN myadd : nat ** nat -> nat
DEF myadd == + De ez is írható DEF myadd(l,r) == +(l,r)

Ha késleltetni szeretnénk egy függvény kiértékelését, akkor azt a következő formában tehetjük meg:

FUN f : nat ** nat -> () -> res LET g == f(1,2) IN expr ...

Ekkor az f függvény csak akkor fog kiértékelődni, amikor a g -t számolnánk ki a kifejezésben.

Maga a függvény törzse egy kifejezés. A kifejezésre erős megkötés vonatkozik. Klasszikusan négyféle dolog lehet kifejezés: az atomi kifejezés, a zárójelezett kifejezés, a függvény használat és az elágazás. Ezen kívül, hogy a funkcionális programozás kifejezőerejét megnöveljék bevezették a lambda absztrakció, a szekció és a lokális deklaráció fogalmát. Atomi kifejezés:

A legtöbb egyszerű kifejezés atomi. Tulajdonképpen két fél atomi kifejezés van: az azonosító és a megjelölés.

Az azonosító mindennek lehet a neve (függvény, globális, vagy lokális változó). A programszövegbe ágyazott fix karaktersorozatok (pl. “Hello Wrold”), pedig a megjelölés, vagy eredetiben denotation típusba tartozik.

Lokális deklaráció

Egy függvényen belül lehetőséget biztosít lokális struktúrák használatára. Kétféleképpen írható:

LET o_1 == kif1
 o_2 == kif2
 ...
 o_n == kifn
IN kif

vagy:

kif WHERE o_1 == kif1
 o_2 == kif2
 ...
 o_n == kifn

Érdekesség, hogy a lokális változók transzformálhatók lambda absztrakcióvá. A fenti példa első transzformációja így néz ki:

(\\o_1. LET o_2 == expr_2
 ...
 IN expr ) (expr_1)