Az Opal programozási nyelv

Utasítások, vezérlési szerkezetek

Zárójelezett kifejezés

Nem sok mondanivaló van róla. Zárójel segítségével csoportba zárt kifejezések.

(“Hello World, 1, +(3,5))

Egy Tuple ami egy denotation-t, egy konstans függvényt és egy végrehajtható függvényt hoz létre. De ennek a gyakorlatban nem sok jelentősége van magában. Viszont igen jól alkalmazható paraméterátadások esetén, mivel a Tupel az Opal-ban flat típusú, azaz (a,b,c, (d,e)) ekvivalens (a,b,c,d,e)-vel.

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

Ekkor a következő kifejezés értelmes és a megkívánt módon működik: f(3, divmod(22,5)) mivel ebből f(3,(4,2)) lesz, ami egyenértékű az f(3,4,2)-vel.

Függvény használat

Ez tulajdonképpen nem más, mint egy atomi kifejezés és egy zárójelezett kifejezés összekapcsolása.

rabbits(generation - 1)
+(3,5)

A függvények használatakor több írási mód lehetséges. Így (3,5)+ és a +(3,5) ugyanazt jelentik. Kicsit használhatóbb ha a pre- és postfix jelölést mondjuk a ! műveletre alkalmazzuk. Ha a ! függvény a faktoriális művelet, akkor ugyanúgy jelölhetjük egy szám faktoriálisát mint ahogy azt a matematikában már megszoktuk.

Az Opal jelölésrendszerében sokféleképpen leírhatunk egy függvényt. pl.:

f(a,b,c); f(a,(b,c)); (a)f(b,c); a f (b,c); (a,b) f c; (a,b,c)f és ezek mind ekvivalensek.

Amire viszont figyelni kell, hogy az egyenrangú függvények mindig jobbról-balra értékelődnek ki.

FUN :: : data ** seq -> seq

Ekkor az 1 :: 2 :: 3 :: 4 :: <> utasítás (<> az üres sorozat) így néz ki zárójelezve: 1 :: ( 2 :: (3 :: (4 :: <> ))) ==> a sorozat 4 3 2 1-et fog tartalmazni.

Ez viszont string konkatenációnál pont jó.

“ab” ++ “cd” ++ “ef” ++ “gh” = “ab” ++ ( “cd” ++ ( “ef” ++ “gh”) ) = “abcdefgh”

A Opal tervezői külön felhívják a figyelmet arra, hogy a 20-10-5 az 15-öt fog eredményül adni, ezért használjunk zárójeleket.

Elágazás

Az elágazás egy vezérlési szerkezet. Általános alakja:

IF felt1 THEN kif1.
IF felt2 THEN kif2.
...
FI

Ezen kívül lehet ELSE ágat és OTHERWISE ágat csinálni.

Mivel az elágazások nem determinisztikusak, ezért a kiértékelés sorrendje nem függ attól, hogy milyen sorrendben írtuk le az elágazás ágait.

DEF max(m,n) ==
IF m >= n THEN m
IF n >= m THEN n

Viszont egy ilyen esetben csak az egyik ágat fogja kiértékelni, ha m = n.

Mivel az Opal szigorú nyelv, ezért viszont egy and kapcsolat mindkét oldalát ki fogja értékelni. Így a következő hibába eshetünk:

IF (~(list empty?) and (ft(list) = 0)) THEN ...
...
FI

Itt ugyanis az első parancs megnézi , hogy üres-e a lista. De ha üres, akkor is kiértékeli második feltétet, ami az első elemét érné el a listának. Ami üres lista esetén abortálni fogja a programot. Erre a problémára két megoldást láthatunk.

IF ~(list empty?) THEN
 IF ft(list) = 0 THEN ...
 ...
 FI
...
FI

 

IF ( ~(list empty?) ANDIF (ft(list) = 0 ) ) THEN ...
...
FI

Az első esetben kikerültük az and használatát egy másik IF THEN FI szerkezettel. A második esetben egy új nyelvi elemmel oldottuk meg a problémát. Természetesen létezik ORIF is, és ez is a lusta kiértékelés szerint halad.

(Már korábban említettem, hogy egy függvény is azonnal kiértékelődik, és egy másik függvény közbeiktatásával lehet csak a lusta kiértékelésre bírni a nyelvet.)

Az OTHERWISE és az ELSE leírását vissza lehet vezetni egyszerű IF-es szerkezetre.

IF cond_1 THEN part_1
...
IF cond_n THEN part_n
OTHERWISE
IF cond_n+1 THEN part_n+1
...
IF cond_n+m THEN part_n+m
FI

Ami ekvivalens a következő kifejezéssel:

IF cond_1 THEN part_1
...
IF cond_n THEN part_n
IF ~(cond_1 or ... or cond_n) THEN
 IF cond_n+1 THEN part_n+1  ...
 IF cond_n+m THEN part_n+m
 FI
FI

 

IF cond_1 THEN part_1
...
IF cond_n THEN part_n
ELSE expr
FI

Ez a szerkezet, pedig a következővel azonos:

IF cond1_THEN part_1
...
IF cond_n THEN part_n
OTHERWISE
IF true THEN expr
FI

Lambda absztrakció

Ezzel lehet név nélküli függvényt létrehozni:

LET a == pi
 b == e
 c == "-5.0"!
IN integeral(\\x.a*x*x + b*x + c, 0, 1)

Ez a kifejezés az integrál függvénynek egy olyan objektumot adott át amelyet előre nem deklaráltunk.

A lambda absztrakcióval természetesen névvel ellátott függvényeket is definiálhatunk.

DEF f(a,b)(c) == expr

ezzel ekvivalens a következő kifejezés:

DEF f == \\a,b. \\c. Expr

(Az f függvény mindkét esetben: FUN f : p1 ** p2 -> p3 -> res típusú)

A lambda absztrakcióval kapott függvény paramétereit, ugyanúgy adjuk meg mint a sima függvényét:

(\\x. X=3) (4)

Ez a függvény megnézi, hogy a paraméter értéke egyenlő-e 3-mal, és bool típussal tér vissza. (azaz ez esetben FALSE-sal)

Szelekció

A szelekció a lambda absztrakció egy leegyszerűsített változata. A szelekció egyszerűbb jelölés rendszert ad függvény definiálásra.

A 3 hozzáadása egy paraméterhez, Lambda absztrakcióval:

(\\x. 3 + x) (1)

És szelekcióval:

(3 + _) (1)

Vigyázat. A szóköz kötelező az + és az _ -ás jelek közé, mivel egyébként azt hiszi a fordító, hogy a +_ függvényt paramétereztük csak a 3-mal!

Ez a módszer több paraméter esetén is használható, ilyenkor a felsorolás sorrendjétől függ, hogy melyiket hova helyettesíti a fordító:

f(a,b,c,d,e) <==> f(a,b,_,_,e) (c,d) <==> ((f(a,_,_,_,e)(b,_,d))(c))