Lisp (programozási nyelv)

A Wikipédiából, a szabad enciklopédiából
Lisp
Paradigma többelvű: funkcionális, procedurális, reflexív, meta programozás
Megjelent 1958
Tervező John McCarthy
Fejlesztő Steve Russell, Timothy P. Hart, and Mike Levin
Típusosság dinamikus típusosság, erősen típusos
Dialektusok Arc, AutoLISP, Clojure, Common Lisp, Emacs Lisp, ISLISP, Newlisp, Scheme, SKILL
Hatással volt rá IPL
Befolyásolt nyelvek CLU, Dylan, Falcon, Forth, Haskell, Io, Ioke, JavaScript, Logo, Lua, Mathematica, MDL, ML, Nu, OPS5, Perl, Python, Qi, Rebol, Racket, Ruby, Smalltalk, Tcl

A Lisp programozási nyelv (helyesebben nyelvcsalád) hosszú történetre tekint vissza. Eredetileg rekurzív függvények absztrakt ábrázolására tervezték, de hamarosan a mesterséges intelligencia kutatás előszeretettel alkalmazott nyelvévé vált, amikor a 70-es, 80-as években ezen terület a virágkorát élte. Ma a Lisp nyelveket számos területen alkalmazzák[1], és közkedvelt a számításelmélet oktatásában is.

A Lisp név az angol „List Processing” (listafeldolgozás) kifejezésre vezethető vissza (maga a lisp szó angolul pöszét, pöszítést jelent.) A Lisp nyelvek fő adatstruktúrája ugyanis a láncolt lista. Az alapvető listakezelő műveletek az összes nyelvjárásban megegyeznek. Emellett közös sajátosság a futásidejű típusosság, a funkcionális programozásra jellemző jegyek, és az, hogy a programkód adatként manipulálható.

Tetszőleges Lisp nyelven írt program azonnal felismerhető a jellegzetes szintaktikájáról. A programkód ugyanis egymásba ágyazott listák, azaz zárójelezett, ún. S-kifejezések (S-expression, sexp) sorozata. Ennek a primitív szintaktikának köszönhetően a Lisp nyelveken írt programokhoz nagyon egyszerű elemzőt (parser-t) és kódot generáló (meta-) programokat írni, ugyanakkor emberi szemmel könnyű elveszni a nyitó- és csukózárójelek erdejében. A könnyű elemezhetőség volt az egyik oka a nyelv népszerűségének a 70-es években, amikor még nem volt elegendő számítási kapacitás összetett, többmenetes fordító- és értelmezőprogramok futtatásához.

Formális specifikációjának első, 1958-ban készített változatával a Lisp a harmadik legöregebb magas szintű programozási nyelv (a Speedcoding és a Fortran után). A megalkotása óta elmúlt közel 50 évben a nyelv sokat változott, és számos nyelvjárással gazdagodott. A ma legelterjedtebb változatai az általános célú Common Lisp és Scheme nyelvek.

Történet[szerkesztés | forrásszöveg szerkesztése]

Az Information Processing Language (Információfeldolgozó nyelv) volt az első mesterséges intelligencia nyelv, amelyet 1955-56-ban alkottak meg, és amelyben már számos, a Lispben alapvető koncepció felbukkant, úgy mint a láncolt listák és a rekurzió.

A Lisp nyelvet John McCarthy alkotta meg 1958-ban, mialatt az MIT-n dolgozott. Eredményeit 1960-ban publikálta („Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I.”). Cikkében rámutatott, hogy pár egyszerű operátor és egy függvények ábrázolására alkalmas primitív szintaktika segítségével teljes értékű, általános programozási nyelv alkotható. A matematikában ez a gondolat Alonzo Church újfajta matematikai logikai rendszere, az 1930-as és 40-es években kidolgozott lambda-kalkulus révén már korábban ismert volt.

Az első Lisp értelmezőt Steve Russel készítette egy IBM 704 típusú számítógépre, amelynek két alacsony szintű utasítása a nyelv két legfontosabb, listák felbontására használt függvénye lett: car (Contents of Address Register) és cdr (Contents of Decrement Register, olvasd, mint: cooder). A legtöbb ma létező Lisp nyelvjárás még mindig ezt a két operátort használja listák fejének, azaz első elemének, ill. farkának, azaz az összes többi elemének a lekérdezéséhez.

A Lisp kifejező erejének és rugalmasságának köszönhetően gyorsan népszerűvé vált a mesterséges intelligencia kutatói közösség körében. Számos előnye mellett a Lispnek természetesen megvannak az árnyoldalai: a programok jelentős mennyiségű, részeredményként szolgáló adatot gyártanak, amelyek foglalják a memóriát. Az ilyen rövid időre lefoglalt memóriaterületeket rendszeresen fel kell szabadítani egy ún. hulladékgyűjtő algoritmus (garbage collector) segítségével. Ez komoly problémát jelentett a 70-es évek memóriában és számítási kapacitásban szűkölködő számítógépeinek. Az egyre növekvő felhasználói tábor igényeinek és kormányzati támogatásnak köszönhetően végül megszületett a Lispgép, azaz a célzottan Lisp programok futtatására készített számítógép. Mára a hulladékgyűjtő algoritmusok, a fordító- és értelmezőprogramok fejlődésének, a memória- és számítási kapacitás robbanásszerű növekedésének következtében a Lispgépekhez hasonló dedikált megoldások feleslegessé váltak.

Az 1980-as és 90-es években komoly energiát fordítottak az egyre jobban eltávolodó nyelvjárások egyesítésére, ennek eredménye a Common Lisp, amely magába foglalta a kiváltani kívánt dialektusok összes lényeges tulajdonságát. 1994-ben az Amerikai Szabványügyi Hivatal, az ANSI nyilvánosságra hozta a nyelvjárást specifikáló szabványt (ANSI X3.226-1994). Ekkorra azonban a Lisp használata a 70-es évek virágkorához képest már jelentősen visszaszorult.

A számítógép-programozásban ma alapvető és teljesen általános esetszétválasztásos (ha … akkor …, egyébként …) vezérlési szerkezetet McCarthy vezette be a Lispben, amelyet aztán az ALGOL átvett és népszerűsített.

Szintaxis[szerkesztés | forrásszöveg szerkesztése]

A Lisp kifejezésorientált nyelv. Ez annyit tesz, hogy a legtöbb nyelvvel ellentétben a Lispben nincs különbség „kifejezések” és „parancsok” között, minden adatot és utasítást kifejezések formájában írunk le. Amikor az értelmező kiértékel egy kifejezést, eredményként egy értéket (vagy értékek listáját) kapunk, amely aztán beágyazható újabb kifejezésekbe, vagy akár kifejezésként maga is kiértékelhető.

McCarthy 1958-as cikke két kifejezéstípust különböztetett meg: Az S-kifejezéseket (S-expression, sexp), vagyis szimbolikus kifejezéseket, és az M-kifejezéseket, vagyis meta kifejezéseket, amelyek S-kifejezéseket alakítanak át újabb S-kifejezésekké. Ez utóbbi típus azonban nem talált támogatókra, és a legtöbb mai Lisp változat S-kifejezéseket használ mind az adatok, mind a kód manipulálásához.

Sokan kritizálták a zárójelek túltengését az S-kifejezésekben (ezt tükrözi a Lisp mozaikszó ironikus kifejtése, a „Lots of Irritating Superfluous Parentheses”, azaz „rengeteg irritáló és felesleges zárójel” is), de az igazság az, hogy az egyszerű, rendkívül szabályos szintaktika adja a Lisp legfőbb erejét: a lehetőséget, hogy a kódot adatként kezeljük.

Az, hogy mindent kifejezésekkel írunk le, nagy rugalmasságot biztosít a nyelvnek. Mivel a Lispben magukat a függvényeket is listákként definiáljuk, akként is tudjuk kezelni őket, és nem okoz technikai nehézséget programot generáló programok írása (ezt hívjuk metaprogramozásnak). Számos Lisp nyelvjárás ki is aknázza ezt a tulajdonságot, és lehetővé teszi makrók készítését, amelyek tkp. függvényeket generáló, paraméterezhető függvények.

A Lisp-ben egy listát zárójelekkel határolunk, az elemeket szóközzel választjuk el egymástól:

(1 2 "izé")

Ezen lista elemei az 1, 2, és az "izé" értékek. Az értékek típusa implicite adott (azaz nem kell – nem is lehet – külön megadni a típusukat): az első kettő egész, a harmadik pedig szöveges (ún. karakterlánc, string). Az üres listát a () kódsorozattal vagy a nil kulcsszóval írhatjuk le.

A kifejezéseket szintén lista alakban írjuk, mégpedig prefix jelölést használva. A lista legelső eleme egy művelet (angolul form), azaz egy függvény, operátor, makró stb. neve. A lista további elemei adják a művelet argumentumait. A list függvény például visszaadja az argumentumaiból alkotott listát, tehát a

(list 1 2 "izé")

kifejezés az (1 2 "izé") értékké egyszerűsödik. Függvény- vagy operátor-művelet esetén az argumentumok a művelet elvégzése előtt rekurzíve kiértékelődnek, értékük behelyettesítődik az eredeti kifejezésbe, amely csak ezután értékelődik ki, például a

(list 1 2 (list 3 4))

kifejezés értéke (1 2 (3 4)). (Az elemi, tovább már nem egyszerűsíthető értékek, mint az 1, 2, és az "izé" mindig önmagukat adják eredményül.) Vegyük észre, hogy a lista harmadik eleme egy másik lista, a listák tehát egymásba ágyazhatóak.

A számtani műveletek hasonlóan működnek (itt szokatlan lehet a prefix jelölés):

(+ 1 2 3 4)

értéke 10.

Bizonyos rendhagyó műveletek (special form-ok) vezérlési szerkezetként szolgálnak. Az if művelet például három argumentumot vár. Ha az első argumentum nem az üres listát (azaz nem a nil értéket) adja eredményül, akkor a második, ellenkező esetben a harmadik argumentumát értékeli ki. Így tehát a

(if nil
  (list 1 2 "izé")
  (list 3 4 "bigyó"))

eredménye (3 4 "bigyó"). Vegyük észre, hogy itt az argumentumok nem értékelődnek ki a művelet elvégzése előtt, mivel nem függvényhívásról vagy operátor alkalmazásáról van szó. Jelen esetben az sem okozna tehát gondot, ha az akkor ágon hibát okozó kifejezés állna.

Egy másik rendhagyó művelet, a defun, függvények definiálására szolgál. Argumentumai rendre a definiálni kívánt függvény neve, a névleges argumentumainak listája, valamint a függvény törzsét alkotó kifejezés (vagy ezek listája), amelynek értéke (kifejezéslista esetén az utolsóé) egyúttal a függvény eredménye is:

(defun miez (a b)
  (list 1 a 3 b))

függvénydefiníció után a (miez 2 4) kifejezés értéke (1 2 3 4) lesz.

Párok és listák[szerkesztés | forrásszöveg szerkesztése]

A Lisp nyelvben a listák egyszeresen láncolt listák. A lista celláit cons celláknak (sokszor egyszerűen pároknak) nevezzük. Egy cons cella két mutatóból áll, amelyeket car-nak és cdr-nek hívunk. Ezen elnevezések eredete az első Lisp megvalósításig nyúlik vissza, az akkori IBM számítógépeken ugyanis így nevezték a Lisp értelmező által használt hivatkozásfeloldó műveleteket (amelyek elérték a mutatók átal megcímzett memóriaterületet). A cons cellákból tetszőleges adatszerkezet építhető, a leggyakoribb azonban a szabályos lista, amelynek car mutatója a lista első elemére, cdr mutatója pedig a farkára, tehát kivétel nélkül vagy a nil szimbólumra vagy egy másik, egy elemmel rövidebb szabályos listára mutat.

Mint látjuk, a listák nem atomi értékek, hanem cons cellák láncolt sorozatai. Egy listára hivatkozó változó nem más, mint a lista első cons cellájára hivatkozó mutató. Egy lista bejárása a cdr függvény sorozatos meghívásával lehetséges, amellyel tehát a listát alkotó cons cellákat látogatjuk sorra.

Egy zárójelezett S-kifejezés egy ilyen láncolt listát definiál. Ugyanazon lista ábrázolására S-kifejezésként számos lehetőség kínálkozik. Egy cons cellát felírhatunk az ún. pontozott pár jelöléssel (a . b) alakban, ahol a a car, míg b a cdr mutató. Ezt az alakot hívjuk kanonikus alaknak. Egy ebben az alakban felírt lista a (1 . (2 . (3 . (4 . nil)))) formát ölti. Ennek az egyszerűsített írásmódja a (1 2 3 4) forma. A két alak keverhető is, azaz ugyanezt a listát felírhatjuk (1 2 . (3 4)) vagy (1 2 3 4 . nil) alakban is. A pontozott pár alak arra is lehetőséget ad, hogy nem szabályos listát alkotó cons cellákat hozzunk létre: (1 2 . 3): itt az első cella cdr mezője ugyan a második cellára mutat, a másodiké viszont a 3 értékre. Párokat létrehozhatunk a cons beépített függvény segítségével is, amely két argumentumot vár, rendre a car és a cdr mutatók értékét.

A párok sokrétű felhasználhatóságának köszönhetően elterjedt, de téves vélekedés, hogy a Lisp-ben nincs is más adatstruktúra. Valójában azonban a legtöbb Lisp megvalósítás tartalmaz más struktúrákat is, mint például a vektorok (vagy tömbök), hash táblák stb.

Megosztott struktúra[szerkesztés | forrásszöveg szerkesztése]

A Lisp listák, lévén hogy egyszerű láncolt listák, tartalmazhatnak közös, megosztott szakaszokat. Nevezetesen, két (vagy több) listának lehet ugyanaz a farka. Például az alábbi kód hatására

(setq ize (list 1 2 3))
(setq bigyo (cons 0 (cdr ize)))

az ize és bigyo változók rendre az (1 2 3) és a (0 2 3) értéket veszik fel. A (2 3) szakasz közös, ha ez valamilyen módon megváltoztatnánk, mindkét lista értéke megváltozna. Ez a megosztás nagyon kedvező hatással van a teljesítményre és a programok memóriaigényére, ugyanakkor könnyen válhat hibák forrásává, ha olyan függvényeket használunk, amelyek destruktív módon manipulálják a listákat.

A tisztán funkcionális programozás hívei éppen ezért elkerülik a destruktív függvények használatát. A Scheme-ben, amely a Lisp funkcionális jellegére nagy hangsúlyt fektet, a destruktív függvények neve egy-egy figyelemfelkeltő felkiáltójelben végződik, mint például set-car!, amely felülírja egy pár első tagját. A Common Lisp nyelvjárásban a desktruktív függvények jóval gyakoribbak, sőt, a nyelv definiál egy rendhagyó műveletet (a setf-et) is, amely desktruktív függvények létrehozását és használatát hivatott megkönnyíteni.

Önazonos kifejezések és az idézés[szerkesztés | forrásszöveg szerkesztése]

Amikor egy kifejezést kiértékelünk, egy másik, többnyire egyszerűbb kifejezést, értéket kapunk. A (+ 2 3) kifejezés például 5-té egyszerűsödik. Bizonyos kifejezések azonban saját magukká értékelődnek ki. Ilyenek a már említett egészek és a füzérek, de ilyen a nil kulcsszó is.

A Lisp-ben lehetőségünk van arra is, hogy egy értéket megvédjünk a kiértékeléstől. Erre szolgál az idézés, azaz a quote rendhagyó művelet, amelyet röviden egy felülvesszővel (´) is jelezhetünk. Ha például megpróbáljuk kiértékelni az ize kifejezést, akkor vagy az ilyen nevű változó értékét kapjuk, vagy hibát, ha nincs ilyen változó. Ha magát az ize szimbólumot akarjuk felírni, akkor idézetbe kell tennünk: (quote ize) vagy egyszerűen ´ize. Ezzel már könnyen tudunk a nil-hez hasonló önazonos neveket definiálni:

(setq ize ´ize)

Ezután akármilyen mélységben értékeljük ki ize kifejezést, mindig önmagát fogjuk kapni. (Tehát ize értéke ize, aminek értéke megint csak ize stb.)

A makrókat lehetővé tevő nyelvjárások ennél bonyolultabb idézőjeleket is definiálnak, mint például a részleges idézést (backquote vagy quasiquote, jele a hátravessző, `). Ennek hatása majdnem azonos a hagyományos idézéssel, azt kivéve, hogy egy vesszővel lehetőség van visszaváltani idézett módból kiértékelendő módba egy-egy részkifejezés erejéig, ezzel kényelmesen változókat ágyazhatunk egy nagyobb idézett kifejezésbe.

Az önazonos és az idézett kifejezések alkotják a Lispben a konstansokat. (Bár ez az elnevezés nem pontos, mert a gyakorlatban lehetőség van ezek értékének megváltoztatására is, amely komoly félreértésekre és zavarokra adhat okot. Elképzelhető például, hogy az ´ize kifejezés egy előfordulása – tkp. egy hivatkozás – kiértékeléskor nem ize, hanem más értéket szolgáltat. Ez mindenképp kerülendő.)

A programkód listaszerkezete[szerkesztés | forrásszöveg szerkesztése]

Az eddigi példákban szereplő karaktersorozatok szigorúan véve nem Lisp programok, csak azok írott reprezentációi. Amikor beírjuk őket a Lisp értelmezőbe, az elemző (a Lisp esetében a read függvény) azonnal átalakítja őket láncolt listákká és fa struktúrákká. A Lisp makrók ezeken a struktúrákon, nem pedig az írott reprezentáción manipulálnak. A legtöbb más nyelvnél az elemző kimenete szigorúan belső, csak a fordító- vagy értelmezőprogram által elérhető adat. A C-ben ugyan vannak makrók, ám ezek a programszöveg előfeldolgozása (preprocesszálása) során aktiválódnak, mielőtt az elemző megkezdené a munkáját.

Egyszerű Lisp megvalósításokban az értelmező közvetlenül ezt a belső formát dolgozza fel a program futtatásához, azonban a legtöbb létező implementáció a hatékonyság érdekében futtatás előtt egy alacsonyabb szintű byte-kódra (adott esetben gépi kódra) fordítja a függvényeket.

Kiértékelés és a OKK (REPL)-ciklus[szerkesztés | forrásszöveg szerkesztése]

A Lisp rendszereket gyakran egy interaktív parancssoron keresztül vezéreljük, amelyet adott esetben kiegészíthet egy integrált fejlesztői környezet (IDE). A felhasználó vagy közvetlenül a parancssorba írja be a kifejezéseket, vagy utasítja a környezetet, hogy tegye meg ezt helyette (mondjuk egy állományból). A Lisp értelmező először beolvassa az adott kifejezést, ezután kiértékeli azt, végül kiírja az eredményt. Ennek megfelelően a Lisp parancssori végrehajtást gyakran "olvasás-kiértékelés-kiírás" vagyis OKK-ciklusnak, angolul "read-eval-print-loop"-nak, REPL-nek hívjuk.

A ciklus három ütemének egy-egy alapvető Lisp függvényt lehet megfeleltetni.

A read függvény beolvassa egy S-kifejezés írott reprezentációját, eredményként annak belső ábrázolását adja. Ha például bemenetként a (+ 1 2) szöveget kapja, egy listát leíró, cons cellákból álló láncolt struktúrát ad eredményül, amelynek első eleme a + szimbólum, második és harmadik eleme pedig rendre az 1 és 2 egészek. Ez történetesen érvényes programkód is, azaz kiértékelhető, mert az első helyen álló szimbólum egy operátor, amely alkalmazható a további elemekre, mint argumentumokra.

Az eval függvény kiértékeli az argumentumaként kapott listaszerkezetet, egy újabb struktúrát adva eredményül. Ez technikailag nem feltétlenül értelmezést jelent, mivel a Lisp megvalósítások programkódot először gyakran gépi kóddá fordítják, majd az így kapott kód futtatását a processzorra bízzák. A gyakorlatban azonban kényelmes értelmezésként gondolni rá: elsőként rekurzíve kiértékelődnek az argumentumok, majd ezek értékére alkalmazzuk a lista fejében hivatkozott függvényt vagy operátort, jelen esetben az összeadást. Az eredményként kapott érték (itt 3) a teljes kiértékelés végeredménye is egyben.

A print függvény feladata az argumentuma megjelenítése a felhasználónak. Egyszerű értékek esetén ez a feladat triviális, bonyolultabb struktúrák, listák esetében azonban a teljes struktúra bejárását igényli.

Ezen három függvény megléte esetén egy primitív OKK-ciklus írása nagyon egyszerű:

 (loop (print (eval (read))))

ahol a loop rendhagyó művelet újra és újra kiértékeli az argumentumaként kapott kifejezést, a végtelenségig.

Példaprogramok[szerkesztés | forrásszöveg szerkesztése]

Alább olvasható pár jellegzetes Lisp példaprogram. Mivel a rekurzió, amely a Lisp nyelvnek jellegzetes vonása, számos matematikai definíció alapja is, a szintaktika elsajátítása után az ilyen definíciók lefordítása Lisp-re nem okoz különösebb nehézséget. A példák ilyen definíciók Lisp-beli megfelelői. Az első függvény a jól ismert faktoriális függvény egy lehetséges megvalósítása:

(defun factorial (n)
  (if (<= n 1)
    1
    (* n (factorial (- n 1)))))

Álljon itt egy másik változat, amely a legtöbb Lisp megvalósításban hatékonyabb, mert jobbrekurzív, azaz a függvény törzsének, legutolsó, legkülső hívása a rekurzív hívás, és ez lehetőséget ad optimalizálásra:

(defun factorial (n &optional (acc 1))
  (if (<= n 1)
    acc
    (factorial (- n 1) (* acc n))))

Vegyük észre, hogy itt a részeredmény egy külön argumentumban (az akkumulátorban) gyűlik.

Ellenpontként következzék egy iteratív változat a Common Lisp ciklusszervező loop makróját használva (ez a makró nem azonos az előbb látott loop-pal):

(defun factorial (n)
   (loop for i from 1 to n
         for fac = 1 then (* fac i)
         finally return fac))

Az alábbi függvény egy listát fordít meg (a Lisp-ben valójában van egy azonos nevű, azonos funkcionalitású beépített függvény):

(defun reverse (l &optional acc)
  (if (atom l)
    acc
    (reverse (cdr l) (cons (car l) acc))))

Megvalósítások[szerkesztés | forrásszöveg szerkesztése]

A Lisp nyelveknek számos megvalósítása készült. A legkorábbiak értelmezőprogramok voltak, habár a Lisp programok gépi kódra fordításra is hamar terjedni kezdett. Az 1980-as években néhány cég ún Lispgépeket kezdett gyártani és forgalmazni – ezek a számítógépek eleve Lisp programok futtatására voltak tervezve és optimalizálva. A modern Common Lisp rendszerek túlnyomó többsége gépi kódra fordítja a programokat futtatás előtt, a legtöbb Scheme megvalósítás ugyanakkor ma is értelmezőprogram alapú. Lisp megvalósítások alapjául szolgálhat a SECD virtuális gép is.

Nyelvjárások és változatok[szerkesztés | forrásszöveg szerkesztése]

Közel ötven éves története során a Lisp-nek számos nyelvjárása jött létre. Mindegyikben közös az S-kifejezések szerepe és szerkezete. Ezen túlmenően a legtöbb nyelvjárásnak több megvalósítása is készült, a népszerű CommonLisp-nek például több mint egy tucat implementációja ismert.

Az egyes nyelvjárások között komoly eltérések lehetnek. A Scheme és a Common Lisp például még az olyan alapvető kérdésekben is eltér, mint a függvényeket definiáló művelet neve. Ugyanazon dialektus különböző megvalósításai azonos szintaktikát követnek és ugyanazokat a beépített függvényeket definiálják, a könyvtári függvények készlete azonban már eltér.

(Figyelem: az alábbi lista vegyesen tartalmaz különféle nyelvjárásokat és megvalósításokat, távolról sem teljes, és nem tükröz fontossági, népszerűségi vagy időrendi sorrendet!)

  • Lisp – McCarthy eredeti megvalósítása, amely az MIT-n készült.
  • Common Lisp – Alapvetően a ZetaLISP-re és a Franz Lisp-re, kisebb mértékben az InterLISP-re támaszkodva hozták létre, ez ma a de facto ipari szabvány.
  • MacLisp – Az eredeti Lisp egyenes ági leszármazottja, az MIT-n fejlesztették ki. (A Mac előtag nem az Apple Macintosh számítógépre, hanem McCarthy nevére utal.)
  • ZetaLisp – A Lispgépek által használt nyelv, a MacLisp továbbfejlesztése.
  • InterLisp – Szintén az MIT fejlesztése a Xerox Lispgépeihez, "nyugati parti" (west coast) Lispként is hivatkoznak rá. A csökkentett, "InterLISP 65" névre hallgató változatát kiadták Atari 6502 típusú számítógépekre is.
  • Franz Lisp – eredetileg a Berkeley egyetem fejlesztése, később a Franz cég vette át.
  • Gold Hill Common Lisp – A Common Lisp egy korai PC-s megvalósítása.
  • Coral Lisp – Lisp értelmező Macintosh számítógépekre.
  • Scheme – Egy eredetileg oktatási célokra tervezett, minimalista Lisp megvalósítás.
  • AutoLISP/Visual LISP – Az AutoCAD testreszabáshoz használható nyelve.
  • Emacs Lisp (ELisp) – Az Emacs szövegszerkesztő szkriptnyelve.
  • Oaklisp – A Scheme objektumorientált kiegészítése, amelyben az osztályok is elsőrendű (azaz programból manipulálható) objektumok.
  • Guile – A Scheme GNU megvalósítása.
  • Cambridge Lisp – Eredetileg IBM mainframe számítógépekhez készült, később a Metacomo cég Amiga számítógépekhez is kiadta.
  • Lispkit Lisp – Egy tisztán funkcionális ("tiszta Lisp") nyelvjárás és megvalósítása a SECD virtuális gépre, leggyakrabban funkcionális programozási elvek kipróbálására és tesztelésére használják.
  • Symmetric Lisp – Egy párhuzamos programozást lehetővé tevő, Common Lisp-ben megvalósított Lisp nyelv, amelyben a környezetek elsőrendű objektumok.
  • STING – A Scheme egy párhuzamosított változata, amely szimbolikus programozási nyelvek operációs rendszereként hivatott szolgálni. Szolgáltatásai között megtalálhatók az elsőrendű szálak, processzorok és testreszabható ütemezési stratégiák.
  • *LISP (STARLISP) – A Common Lisp Egy adat-párhuzamos megvalósítása.

Lásd még[szerkesztés | forrásszöveg szerkesztése]

További információk[szerkesztés | forrásszöveg szerkesztése]