Több Lisp változat csak egész típusú számokat enged használni, de a Common Lisp már több fajta számtípusokat különböztet meg és enged használni. Ezek az
integer – egész
ratio – racionális
float – lebegőpontos
complex - komplex
Együttesük a number típus, amely magába foglalja az összes számtípust. Vagyis a fenti típusok a number típus altípusai.
A number típus felépítése:
number ::= real | complex
real ::= rational | float
rational ::= integer | ratio
Az elnevezések a matematika terminológiáját követik, de nem feltétlenül pontosak. Az integer és a ratio típus pontosan megegyező a matematika terminológiájával. A float típus viszont a valós számok közelítésére használható. A real típus minden Common Lisp-beli számot tartalmaz, amely valós számot reprezentál, viszont vannak olyan valós számok, amelyeknek nincs pontos Common Lisp beli reprezentánsuk. Csak a real típusú számok rendezhetőek a <, >, <= és >= függvényekkel.
A number típusra a megszokott matematikai függvények használhatók (pl. +, -, *, /, floor, ceiling, mod, sin, cos, tan, sqrt, exp, ...). Ezek mindegyike elfogadja argumentumként a fent említett számtípusokat.
A +, -, *, / függvények az eredményt a megfelelő típusra konvertálják. Pl.: (+ 3 3/4) = 15/4
A számok vizsgálatát a numberp függvénnyel végezhetjük el. Ha az argumentum szám akkor a visszatérési értéke true egyébként false.
Egy szám párosságát vagy páratlanságát az oddp evenp függvényekkel vizsgálhatjuk meg. Ezen felül hasznos lehet a minusp és plusp függvény is ami megadja, hogy egy szám negatív vagy pozitív-e.
Gyakran el kell tudnunk dönteni, hogy egy szám értéke nulla vagy valami más. Erre használhatjuk a zerop függvényt.
Az integer típus a matematikai egész számokat reprezentálja. A legtöbb programozási nyelvvel ellenttétben a Common Lisp nem tesz megkötést egy integer hosszára vonatkozóan, tetszőlegesen nagy lehet, a méretet csak a memória mérete korlátozza.
A Common Lisp bármely implementációjában van az integer típusnak egy hossza, ami alatt ezeket hatékonyabban kezeli. Minden ilyen integer neve fixnum. A nem fixnum integereket pedig bignum-nak nevezik. A Common Lisp-et úgy tervezték, hogy ezt a megkülönböztetést a lehető legjobban elrejtse, és csak nagyon indokolt esetben tudassa a felhasználóval a fixnum és bignum közti különbséget. Az, hogy pontosan mely számok tartoznak a fixnum-ok közé implementáció függő, általában a [-2^n,...,2^n - 1], n>=15 intervallum elemei.
integer ::= [sign] {digit}+
sign ::= + | -
digits ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
példák:
A ratio típus a matematikai racionális számokat reprezentálja, azaz azok a számok tartoznak ide, amelyek felírhatók két egész szám hányadosaként. Az integer és a ratio típus együtt alkotják a rational típust. Egy racionális szám kanonikus reprezentációja egy integer, ha a hányados értéke egész, különben egy számláló és egy nevező (egészek), amelyek legnagyobb közös osztója 1 és a nevező pozitív. A hányadost ’/’ jelöli. Lehetséges a racionális számokat nem kanonikusan használni, azaz nem egszerűsítve, de a Lisp prin1 függvénye mindig a kanonikus alakot írja az outputra.
ratio ::= [sign] {digits}+ / {digits}+
sign ::= + | -
digits ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
A második sorozat nem állhat csupa 0 elemekből.
példák:
A Common Lisp több fajta lebegőpontos szám típus implementálását engedélyezi, amelyek együtt alkotják a float típust. Egy lebegőpontos szám egy (matematikai) racionális szám, amely az alábbi formulával írható le:
s*f*b^(e-p), ahol
s +1 vagy -1,
b 1-nél nagyobb egész,
p 0-nál nagyobb egész,
f a [-b^(p-1),...,b^(p-1)] intervallumból való,
e egész.
p értéke és e hossza függ az implementációtól és az implementáción belüli lebegőpontos szám típusától. Például tekintsük a lebegőpontos nullát. Az implementációtól függően létezhet egy „mínusz nulla” is, amely nem azonos a „pozitív nullával”.
A lebegőpontos számok a pontosság és a méret függvényében definiálhatók. Egy jó minőségű, lebegőpontos számokkal operáló alkalmazás a pontosságra törekszik, ennek hátránya a hordozhatóság tulajdonság elvesztése. Pontosan ezért külünböztetünk meg lebegőpontos számokat:
short-float: a legkisebb rögzített pontosság mellett definiált
long-float: a legnagyob rögzített pontosság mellett definiált
single-float, double-float: a short- és a long-float közötti
A lebegőpontos számok BNF-je:
floating-point-number ::= [sign] {digit}* decimal-point {digit}* [exponent]
| [sign] {digit}+ [decimal-point {digit}*] exponent
sign ::= + | -
decimal-point ::= .
digit ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
exponent ::= exponent-marker [sign] {digit}+
exponent-marker ::= e | s | f | d | l | E | S | F | D | L
Ha nincsen exponens megadva vagy ha az exponens jelző e (vagy E), akkor a pontos formátum nincs mehatározva.
Az s, f, d, l (ill. S, F, D, L) rendre a short, single, double, long formátumokat határozzák meg.
példák:
A komplex számokat a szokásos módon reprezentáljuk Lispben, azaz egy valós és egy képzetes résszel. Ezek mindegyike rational típusú, tehát integer, ratio vagy float típusú, de a kettő típusa azonos kell legyen. Ha a listában szereplő számok nem azonos típusúak, akkor a Lisp azonos típusra konvertálja őket.
Egy complex típusú szám könnyen felismerhető, a #C karakterek után egy listában a valós illetve a képzetes számok szerepelnek.
példák:
A karaktereket a character típus foglalja magába. Egy karakter objektumot a #/ jelek után írt karakterrel azonosítunk. #\g tehát egy karakterobjektum a ’kis g’ karakterhez. Ez megfelelően alkalmazható karakterek kiíratásához. A nem látható karakterekhez nevek tartoznak. Például a space név jelenti a szóköz karaktert, tehát ha egy szóközt szeretnénk az outputra kiírni, akkor ezt megtehtjünk a #\space karakterobjektum alkalmazásával.
A Common Lisp definiál egy meghatározott karakterekből álló standard-char altípust. Ennek egyik oka, hogy az a Common Lisp program, amely csak a standard karaktereket használja, azt bármely Common Lisp implementáció képes olvasni. Illetve az a Common Lisp program, amely csak standard karaktereket használ adat objektumként az a program nagy valószínűséggel hordozható.
A standard karakterek a következők:
két nem látható karakter: #\space, #\newline
illetve 94 általános karakter:
A character típus minden objektumának három attribútuma van: code, bits és font.
A code attribútum arra hivatott, hogy megkülünböztesse a karakterek betűképét és formázó funkcióit.
A bits attribútummal extra flag-eket lehet hozzárendelni a karakterekhez.
A font pedig a karakterek képének stílusát állíthatja (pl. félkövér, dőlt...)
példa: font attributum használata: #3\a az a betűt jelenti 3-mas font típussal, ha a 3-mas font típus a görög betűk, akkor ez ekvivalens a #\alfa karakter objektummal.
Minden karakter, amely bits és font attributumai nullák, azok állhatnak egy string belsejében. Az ilyen karaktereket a character típus egy új altípusába soroljuk: string-char.
A tömb egy olyan objektum, melynek komponensei a derékszögű koordináta rendszer szerint rendezettek. Ezek a komponensek tetszőleges Lisp objektumok lehetnek.
Egy tömb dimenzióinak a száma a tömb rangja. A rang egy nem negatív egész szám. Hasonlóképpen minden dimenzió egy nem negatív egész szám. A tömb összes elemének a száma a dimenziók szorzata.
A Common Lisp bizonyos implementációja határt szabhat egy tömb rangjára vonatkozóan, de ez a határ nem lehet kisebb 7-nél. Ebből következően bármilyen Common Lisp program felteheti, hogy a használt tömb rangja 7 vagy annál kisebb. Jelenleg a Common Lisp 25 dimenzióig támogatja a tömböket.
Engedélyezett, hogy egy dimenzió nulla legyen. Ebben az esetben a tömbnek nincsenek elemei és bármilyen hozzáférési kísérlet hibát eredményez. Mindazonáltal a tömb többi tulajdonsága elérhető, mint például a dimenziók maguk. Ha a rang nulla, akkor nincsenek dimenziók, definíció szerint ekkor a tömb elemeinek a száma 1. Azaz egy nulla rangú tömbnek van 1 eleme.
Egy tömb objektumot az indexek sorozata határozza meg. A sorozat hossza megegyezik a tömb elemeinek a számával. Minden index egy nemnegatív egész, amely határozottan kisebb a megfelelő dimenziónál. A tömb indexelése 0-val kezdődik.
Legyen t egy 3x5 dimenziós tömb. Ekkor a tömb elemeire való hivatkozásnál az első index 0,1 vagy 2 míg a második index 0, 1, 2, 3 vagy 4 lehet. A tömb elemeire hivatkozni az aref függvénnyel tudunk. Például (aref t 2 1) a tömb (2, 1)-edik elemére hivatkozik. Ha t nulla rangú lenne, akkor nem írunk indexeket az aref függvénybe és (aref t) a tömb egyetlen elemét adja eredményül.
A tömbök tehát lehetnek többdimenziósak, megoszthatják tartalmukat más tömb objektumokkal és dinamikusan változtathatják (növelhetik vagy csökkenthetik) méretüket a létrehozásuk után.
Tömböt a make-array függvény vagy a #karakter segítségével lehet létrehozni. Az indexelés mindig 0-val kezdődik. Az összes tömbelem kezdeti értéke NIL. Az elemekre indexek alapján lehet hivatkozni az aref függvénnyel. Pl.:
Common Lisp-ben az egydimenziós tömböket egy vector nevű altípusba soroljuk. Ez a típus felel meg a hagyományos vektor típusnak. A vektorok és listák egyaránt sorozatoknak tekinthetők a különbség köztük, hogy a vektor bármely elemét azonnal el tudjuk érni, míg a lista esetében ez egy lineáris művelet. Másrészt egy elem hozzáadása a listához konstans időt vesz igénybe vektor esetében pedig lineáris.
Lisp-ben egy általános vektort (azaz egy egydimenziós tömböt, amelynek elemei tetszőleges típúsú objektumok lehetnek) az elemeik felsorolása jelez a #( és ) szimbólumok között.
példák:
A tömbök egy speciális esetei a bit tömbök. Ezek olyan tömbök melynek elemei csak 0 vagy 1 lehet. Ezek létrehozása a make-array függvénnyel és a #*karakterrel lehetséges.
példák:
A string tehát egy karaktereket (egészen pontosan string-char típusu objektumokat) tartalmazó vektor. Vagyis a string típus a vector típus egy altípusa.
Ezeket a speciális vektorokat jelölésben is megkülönzöztetjük. Egy string típusú objektum, karakterek sorozata amelyeket " jelek határolnak. Ha a " karaktert szeretnénk egy string típus belsejében használni, akkor elé egy \ karaktert kell írnunk.
példák:
A kifejezések alapegységei az atomok. Az atom lehet numerikus (egy szám és az esetleges előjele), illetve szimbolikus (betűkből és számokból álló karaktersorozat, aminek az első karaktere betű). A Lisp alapvető szerkezete a lista. A lista atomokból épül fel úgy, hogy, zárójelek között megadjuk a listát felépítő atomokat szóközzel elválasztva. Egy lista atomokból és listákból állhat.
Az atomokat és listákat összefoglaló néven szimbolikus kifejezéseknek, S-kifejezéseknek vagy röviden kifejezéseknek nevezzük. Az alábbiak tehát S-kifejezések:
S-kifejezések formálisan:
A LISP nyelvben mind a programok, mind pedig az adatok, amelyeken a programok dolgoznak, S-kifejezésekből állnak. Egy LISP program S-kifejezések egymásutánja.
Mindent zárójelezni kell, nincs precedencia. Ennek köszönhetően nagyon egyszerű a nyelvtan. Így könnyen irható olyan program, mely a feladata megoldásához egy másik programot (kifejezések sorozatát) generál. Ez különösen a mesterséges intelligencia alkalmazásoknál fontos.
Beépített konstansok:
A kommenteket ;-vel kell kezdeni. Hatásuk a sor végéig tart. Többsoros komment írására nincs lehetőség.
Az itt leírtak a Common Lisp-re igazak általánosan. Mint minden nyelvben a (Common) Lisp-ben a változók nevesített helyek amelyek értéket tárolhatnak. A Java-val és a C++-al ellentétben a Lisp-ben nem kell megadni típust az objektumnak. Minden változó tárolhat bármilyen típusú értéket, és maga az érték tárolja a típust ami futásidőben lekérdezhető. Ennélfogva a (Common) Lisp dinamikusan típusos nyelv(pl ha + függvénynek nem szám típust adunk meg típus hibát fog dobni). Viszont a nyelv erősen típusos is, tehát minden típushibát detektálni fog. Ha egy változóhoz új értéket rendelünk hozzá, akkor az csak azt változtatja meg, hogy melyik objektumra mutat a változó, de a korábbi objektumot nem változtatja meg. Viszont mutable objektumoknál lehetőség van az objektum módosítására, ami az összes arra az objektumra mutató referenciának látható lesz.
Lexikálisan kötött változok hatóköre fizikálisan arra a környezetre korlátozódik ahol a kötés létrejött. A blokkra nem lexikálisan hivatkozó referenciák nem látják ezeket a változókat. Ez hasonlít a C illetve a Java lokális változóihoz. A lexikális környezet megadásához Common Lisp-ben a LET kulcsszót használjuk. A LET kulcsszó használata:
A modern nyelvek mindegyike elsődlegesen a lexikális(lokális) környezetet támogatja és ajánlja, mert segíti az átláthatóságot. Viszont globális változókra szükségünk lehet, ezért ez szinte minden programozási nyelvben megjelenik. A Lisp megoldása a globális változókra az úgynevezett dinamikus változók, a használhatóság és a kezelhetőség előnyeit. Common Lispben kétféle út van globális változók létrehozásához: DEFVAR és DEFPARAMETER. Mindkettő kér egy változónevet egy kezdőértéket és opcionálisan megható egy dokumentációs string. Globális változóknál konvencionálisan *-gal kezdődik és végződik a név az átláthatóság végett. Pl:
A DEFCONSTANT kulcsszó segítségével lehet „konstans változókat” létrehozni. Ezek mind globális konstansként lesznek definiálva. A DEFCONSTANT alakja:
Ha már megvan a kötés a változóhoz akkor két dolgot tehetünk: Lekérdezzük a jelenlegi értékét vagy újat adunk neki. Új érték adását egy változóhoz Common Lispben a SETF makró segítségével tehetjük meg. Az egyszerűsített alakja a következőképp néz ki: