A Haskell programozási nyelv

Lexikális elemek

Jelkészlet

A Haskellben a Unicode (3.0) karakterkészlet használható, a nyelv korábbi változatai az ASCII karaktereket használták. A kis- és nagybetűket a fordító megkülönbözteti.
A Haskell fordító előfeldolgozója a nem Unicode karaktereket Unicode-ra konvertálja és az \uhhhh escape szekvenciát használja (a "h" itt hexadecimális számjegyet takar), a különleges karakterek esetén.
A továbbiakban a következő BNFszerű szabályokat használjuk ott, ahol a specifikációból idézünk:

[pattern] egyszer vagy egyszer sem (opcionális) {pattern} egy vagy több ismétlődés (pattern) csoportosítás pat1 | pat2 választás pat<pat'> pat kivéve pat' elemeit fibonacci terminális
A Haskell az elrendezés (layout) bevezetésével szükségtelenné teszi a más nyelvekben gyakran megtalálható elhatároló-jelek egy részének (pontosvessző, zárójelek) használatát, ami könnyíti a program olvashatóságát. Ugyanakkor a nyelv támogatja a hagyományos stílust is, ráadásul szabadon kombinálhatók is egy programon belül. Indentált módban a whitespace karaktereket, míg a hagyományos módban ezeken kívül a ; , és { } karaktereket használjuk elhatárolásra.
Az elrendezés segítségével a kihagyott elhatárolók visszaírhatók a programszövegbe. Az algoritmus a következő: ha a fordítóprogram hiányzó nyitózárójelet talál a where, let, do vagy az of kulcsszavak után, megjegyzi a következő lexikális elem indentálását (akár új sorba került akár nem), és beilleszti a hiányzó zárójelet a beolvasott tokensorozatba. Ezek után a következő sorok behúzottsága alapján pontosvesszőket és végül egy csukózárójelet illeszt a tokensorozatba: ha egy sor behúzása megegyezik az eltárolt behúzási szinttel, akkor pontosvesszőt kell beilleszteni, ha kisebb annál akkor vége a blokknak és egy csukózárójel kerül a tokensorozatba. A blokkok többszörös egymásba ágyazhatósága miatt nem elég egyetlen behúzási szintre emlékezni: az algoritmusnak egy vermet kell nyilvántartani az érvényes behúzási szintekkel.

Példa indentált módra:

f x = case x of 0 -> 1 1 -> 5 2 -> 2 _ -> 1 ...

ugyanez nem indentált módban:

f x = case x of { 0 -> 1 ; 1 -> 5 ; 2 -> 2 ; _ -> 1 }

vagy éppen összevissza:

f x = case x of { 0 -> 1 ; 1 -> 5 ; 2 -> 2 ; _ -> 1 }

Azonosítók

Az azonosítók betűvel kezdődnek és betűkkel, számjegyekkel, aláhúzásokkal vagy aposztrófokkal (') folytatódhatnak. Az első betű alapján az azonosítókat két osztályba soroljuk: * a kisbetűvel kezdődő azonosítók változó azonosítók, például name és naMe (a kis- és nagybetűk megkülönböztetettek, ez két különböző azonosító); * a nagybetűvel kezdődő azonosítók pedig konstruktor azonosítók (Pl: Name). Az aláhúzás (_) kisbetűnek számít, de önmagában állva fenntartott szó. Némely fordítóprogram figyelmeztet ha nem használt azonosítókat talál, ilyenkor a figyelmeztetést elnyomhatjuk, ha _-vel kezdjük az adott azonosítót. Mind a változó, mind a konstruktor azonosítók lehetnek kvalifikáltak. A kvalifikáció itt azt jelenti, hogy a lexikális elem elé írjuk ("."-al elválasztva) a modul nevét.

Literálok

Numerikus literálok A numerikus literálok lehetnek egész számok (integer) és lebegőpontos számok (float) 1. Az egész számot tartalmazó literálokat háromféleképpen lehet megadni:

decimal -> digit{digit} octal -> octit{octit} hexadecimal -> hexit{hexit} integer -> decimal | 0o octal | 0O octal | 0x hexadecimal | 0X hexadecimal

Decimális alakban:

ertek_12 = 12

Oktális alakban (0o vagy 0O prefixszel):

ertek_12 = 0o14, ertek_12 = 0O14

Hexadecimális alakban (0x vagy 0X prefix):

ertek_12 = 0xC, ertek_12 = 0XC

2. A lebegőpontos számot tartalmazó literálok mindig decimálisak. Az ezekre vonatkozó lexikális szabály:

float -> decimal . decimal[(e | E)[- | +]decimal]

Például:

ertek1 = 1.2 , ertek2 = 1.2e+3
Feltűnhet, hogy ez a definíció nem tartalmazza a negatív számokat. Ennek oka az, hogy a negatív numerikus literálokat a mintaillesztés speciális eseteként oldották meg.

Karakter és sztring literálok

char -> ' (graphic<'|\> | space | escape<\&>) ' string -> " {graphic<"|\> | space | escape | gap}" escape -> \ ( charesc | ascii | decimal | o octal | x hexadecimal ) charesc -> a | b | f | n | r | t | v | \ | " | ' | & ascii -> ^cntrl | NUL | SOH | STX | ETX | EOT | ENQ | ACK | BEL | BS | HT | LF | VT | FF | CR | SO | SI | DLE | DC1 | DC2 | DC3 | DC4 | NAK | SYN | ETB | CAN | EM | SUB | ESC | FS | GS | RS | US | SP | DEL cntrl -> ascLarge | @ | [ | \ | ] | ^ | _ gap -> \ whitechar {whitechar}\
A fenti táblázatban az alsóindex a 'kivéve ezeket' jelölése.

A karaktereket egyszerű idézőjelek közé írjuk.

karakter1 = 'a' karakter2 = '&' karakter3 = '3'

A sztring literál tulajdonképpen egy rövidítés karakterek listájára. A sztringeket kettős idézőjelek közé írjuk:

string1 = "Hello" string2 = "a" "Hello" == ['H','e','l','l','o']

A karakteres literálokban használható escape sorozatok táblázata:

Excape jelsorozatJelentés
\[decimális szám]a decimális számnak megfelelő karakter
\x[hexadecimális szám]a hexadecimális számnak megfelelő karakter
\o[oktális szám]az oktális számnak megfelelő karakter
\ahangjelzés (alert)
\btörlés (backspace)<
\fform feed
\núj sor (new line)<
\rkocsivissza (carriage return)
\ttabulátor (horizontal tab)<
\vfüggőleges tabulátor (vertical tab)
\\\<
\""
\''<
\&ez az ún. nullkarakter, nincsen hatása, arra jó, hogy lehessen ilyet írni: "\137\&9", ami a 137-es kódú karakterből és a 9-esből álló karakterlánc
\^[ASCII nagybetű]az adott betű és a ctrl együttes lenyomásának felel meg<
\^@
\^[
\^]
\^\
\^^
\^_
\NUL\x00=NULL
\SOH\x01=START OF HEADING
\STX\x02=START OF TEXT
\ETX\x03=END OF TEXT
\EOT\x04=END OF TRANSMISSION
\ENQ\x05=ENQUIRY
\ACK\x06=ACKNOWLEDGE
\BEL\x07=BELL
\BS\x08=BACKSPACE
\HT\x09=CHARACTER TABULATION
\LF\x0A=LINE FEED
\VT\x0B=LINE TABULATION
\FF\x0C=FORM FEED
\CR\x0D=CARRIAGE RETURN
\SO\x0E=SHIFT OUT
\SI\x0F=SHIFT IN
\DEL\x10=DATALINK ESCAPE
\DC1\x11=DEVICE CONTROL ONE
\DC2\x12=DEVICE CONTROL TWO
\DC3\x13=DEVICE CONTROL THREE
\DC4\x14=DEVICE CONTROL FOUR
\NAK\x15=NEGATIVE ACKNOWLEDGE
\SYN\x16=SYNCHRONOUS IDLE
\ETB\x17=END OF TRANSMISSION BLOCK
\CAN\x18=CANCEL
\EM\x19=END OF MEDIUM
\SUB\x1A=SUBSTITUTE
\ESC\x1B=ESCAPE
\FS\x1C=FILE SEPARATOR
\GS\x1D=GROUP SEPARATOR
\RS\x1E=RECORD SEPARATOR
\US\x1F=UNIT SEPARATOR
\SP\x20=SPACE
\DEL\x7F=DELETE

Fenntartott karaktersorozatok

Fenntartott operátorok:

.., :, ::, =, \, |, <-, ->, @, ~
(A @ (mintaillesztés) lényegében egy elnevezése a hivatkozott objektumnak. Gondoljunk az adatbázis kezelésben használatos as –re.)

Fenntartott azonosítók: case, class, data, default, deriving, do, else, if, import, in, infix, infixl, infixr, instance, let, module, newtype, of, then, type, where, _

Tipus lekerdezese: Egy adott kifejezésnek vagy változónak a típusát meg tudjuk, ha a :t illetve a :t parancsot írjuk, a környezet fogja eldönteni a típust. Ha egy függvény típusát kérdezzük meg, akkor visszakapjuk a függvény szintaxisát.

Komment

A megjegyzések whitespace tokennek minősülnek. A -- jelek után a sor végéig, vagy {- és -} jelek között több soron keresztül tartó megjegyzést írhatunk, az utóbbi változat egymásba is ágyazható. Külön dokumentációs megjegyzés nincs, ugyanakkor érdekesség, hogy a "-->" és a "--|" nem komment, ugyanis a lexikális elemző a leghosszabb illeszkedés szabálya alapján dolgozik, és van más '--'-vel kezdődő lexikális elem is (ez a két jel akár egy-egy operátornév is lehetne). Megemlítendő még az ún. literate forrás, amikor minden sor megjegyzés, kivéve a ">"-al kezdődőeket. Ez didaktikai szempontból kényelmes - ami, ne felejtsük el, egyik célkitűzése volt a programnyelvnek.