A LISP programozási nyelv

Symmetric Lisp; környezet, párhuzamosság és alkalmazásai

Környezetek, párhuzamosság

A Symmetric Lisp programozási nyelv a Lisp szintaktikáját követi, és a Lispben megszokott függvényeket támogatja. Lehetővé teszi környezetek írását, amelyek a nyelv objektumai. A környezet (environment) olyan szerkezet, ami szimbólumokat kapcsol össze jelentésükkel vagy értékükkel. Mivel a környezet elemeinek kiértékelése párhuzamosan történik, a Symmetric Lisp párhuzamos programozási nyelv.

A környezetek három elemből állnak: ALPHA, PRIVATE és NAME form. A NAME egy szimbólum nevét kapcsolja össze egy kifejezés értékével. A PRIVATE hasonló a NAME-hez, a különbség csupán annyi, hogy a "PRIVATE szimbólumok" láthatósága csak a definiáló környezetre terjed ki. Az ALPHA form adja meg a NAME/PRIVATE formok jelentését úgy, hogy egy környezetbe fogja össze őket. Az ALPHA formot kiértékelve eredményül egy másik ALPHA formot kapunk, melyben az eredetiben szereplő összes kifejezés értékét meghatároztuk. Az ALPHA-n belüli összes név, függetlenül attól, hogy a NAME vagy a PRIVATE formot használjuk, különböző kell, hogy legyen.

Egy ALPHA kiértékelése három lépésben történik. Először a benne szereplő neveket kell meghatározni, és rögzíteni, hogy ahhoz a környezethez tartoznak, amit az ALPHA definiál. Ez a folyamat minden szimbólum esetében párhuzamosan történik. Ezután a kifejezések szimultán kiértékelése következik. Ha az egyik kifejezés kiszámításához egy másik értékére van szükség, és az még nem meghatározott, akkor a kifejezés kiértékelése blokkolódik addig, amíg a kért érték rendelkezésre nem áll. A harmadik lépésben visszakapjuk az eredmény ALPHA-t, melynek k-adik eleme az eredeti ALPHA k-adik elemének eredménye.

Például:

(ALPHA (NAME x (+ 1 1)) (NAME y (* x 10)))

eredménye

(ALPHA (NAME x 2) (NAME y 20))

Ha a kifejezés olyan névre hivatkozik, ami nem található meg az őt közvetlenül tartalmazó ALPHA-ban, akkor eggyel kijjebbi ALPHA-ban (ami tartalmazza a közvetlent) folytatódik a keresés, és így tovább. Egy szimbólumhoz tartozó értéket meg lehet változtatni a SETQ paranccsal. A SETQ hasonlóan működik, mint a többi Lispben, kivéve, hogy a szimbólum csak egy a NAME vagy PRIVATE form által korábban definiált név lehet. (De: a PROGN itt is szekvenciális kiértékelést jelent!)

Minthogy a környezet first-class object, adhatunk neki nevet, és ha pl. egy környezet neve Q — (NAME Q (ALPHA ...)) — kiértékelhetünk egy E kifejezést Q névterén belül a következő módon:

(WITH Q E). ...

Egy ALPHA elemei tetszőleges kifejezések lehetnek (nem csupán a NAME vagy PRIVATE formok), ezek kiértékelése is ugyanúgy történik. Tehát:

(ALPHA ( NAME x 10 ) (+ x 5))

eredménye

(ALPHA ( NAME x 10 ) 15)

Rekord

Könnyen látható, hogy az eddig mutatott környezetek a Pascal rekord típusához hasonlóan viselkedhetnek, azaz különböző adattagokat összefoghatnak egy struktúrába. Például:

( NAME leonardo ( ALPHA ( NAME job 'printer ) ( NAME city 'florence ) ( NAME century 16 )))

létrehoz egy rekordot. A (WITH leonardo city) eredménye a florence szimbólum. A (WITH! Q E) segítségével megváltoztathatjuk E-t. A

(WITH! leonardo (SETQ job 'literary-critic))

megváltoztatja leonardo "job" mezőjét.

(NAME math-library (ALPHA (NAME pi 3.1415265) (NAME sin LAMBDA (x) <a sin definíciója>) (NAME cos LAMBDA (x) <a cos definíciója>)))

a math könyvtárat definiálja, ahol a LAMBDA függvénykonstans. Tehát pl. (NAME sin LAMBDA (x)) azt mondja meg, hogy a sin egy függvény, melynek egy paramétere van: x. A sin(n) a következőképpen számolható: (WITH math-library (sin n)).

Absztrakt adattípus

A PRIVATE form különösen hasznos akkor, ha nem akarjuk beszennyezni a nyilvános névteret, vagy ha el akarjuk rejteni egy struktúra belsejét. Egy absztrakt adattípus definiálása (műveletek megvalósítása, reprezentáció elrejtése) kézenfekvő példa a PRIVATE formok használatára. A következő példa a környezetek egy másik tulajdonságára is rávilágít, mégpedig arra, hogy függvény visszatérő értéke is lehet környezet:

(NAME queue (LAMBDA (t) (ALPHA (NAME append (LAMBDA (item) <...code for append...> )) (NAME delete (LAMBDA <...code for delete...> )) (PRIVATE rep (make-array : type t )))))

A (NAME q1 (queue integer)) kifejezés a q1 szimbólumhoz rendel egy környezetet, amely integerek sorát reprezentálja. A (WITH q1 (append 3)) kóddal pedig a 3 értéket tesszük a q1 sor végére.

Környezetek időleges viselkedése

Az eddig tárgyalt környezetek statikusak voltak. A környezet által megvalósított szerkezetet nem lehet kibővíteni. Esetenként azonban nem lehetséges egy időben definiálni a környezetet. A Symmetric Lisp a gyarapodó környezetek problémájára vezette be az ún. open alpha formot. Az open alpha nem passzív objektum, hanem folyamatban lévő számítás. Egy open alpha kiértékelése folyamatos, a létrehozásától kezdve korlátlan ideig tart. Az ATTACH! művelettel lehet hozzáadni új elemeket egy open alpha-hoz. Az open-alpha művelet egy új open alpha-t hoz létre, amely egy üres alpha, így

( NAME environ1 (open-alpha))

a következőt adja:

( NAME environ1 (ALPHA * ))

ahol a * azt jelzi, hogy az új elemek itt fognak megjelenni. Az ATTACH!(egy open alpha, kifejezés) függvény hozzáadja a kifejezést az open alpha-hoz. Ahogy a kifejezés hozzáadódik az open alpha-hoz, kiértékelődik. Így az

(ATTACH! environ1 (NAME foobar 1)), environ1

hívás eredménye

( ALPHA ( ALPHA ( NAME foobar 1) * ))

lesz. Az open alpha kiértékelése is párhuzamosan történik.