A Haskell programozási nyelv

Változók és kifejezések

Változó

A Haskell tisztán funkcionális nyelv, aminek jellemzője, hogy nincs előző értéket megsemmisítő értékadásra lehetőség, valamint mellékhatások biztosan nem lépnek fel a nyelvi elemei felhasználása során. További jellemzője a hivatkozási helyfüggetlenség (referential transparency). Ennek a jelentése, hogy ugyanaz a kifejezés a program szövegében mindenhol ugyanazt jelenti. A függvények kiértékelései nem mellékhatásosak, azaz nem változtatják meg a kifejezés értékét, valamint a program változói igazából konstansok. Az utóbbiak értéke esetleg még nem ismertek, de egyértelműek, és a program végrehajtása során nem változhatnak. Ezt az elvet hívjuk egyenlőségi érvelésnek, és ez biztosítja a program funkcionális helyességét.

A Haskellben kétféle változó is van: a "megszokott" értelemben vett változók, illetve a típusváltozók.
A típusváltozóknak függvények típusának megadásánál illetve új típusok készítésénél van szerepe, segítségükkel lehetséges az általánosítás (generic).
A "megszokott" változó - a programozási módszertan szerint - az állapottér egydimenziós projekciós függvénye, és Haskellben így is el lehet képzelni a működését. Következésképp egy változó úgy viselkedik, mint egy nulláris függvény. A lusta kiértékelési rendszer miatt úgy gondolhatunk például egy értékadásra, mint egy függvényátlapolásra. Ennek az a következménye, hogy a változó előző értéke nem vész el - mint az imperatív nyelvekben -, hanem megmarad. (Másik kérdés, hogy a változó régi értéke elérhető-e.) Így persze óvatosan kell bánni az olyan nagy méretű adatstruktúrákkal, mint például a tömbök, cserébe viszont nincsenek mellékhatások.

Szintaxis

A Haskell nyelv érzékeny a kis- és nagybetűk különbségére. Az azonosítók egyébként a szokásos karaktereket tartalmazhatják, különlegesség, hogy tartalmazhatnak még aposztrófot (') is.

Változók típusa

Bár a nyelv típusos, a típus kiírása az esetek legnagyobb részében nem kötelező, mivel a Haskell rendelkezik egy speciális típuskiértékelő rendszerrel (Hindley-Milner-féle rendszer), amely képes kikövetkeztetni a megfelelő típust. Ennek ellenére a típusok explicit kiírása - legalábbis a függvények esetében - célszeru, hiszen így a fordító vagy inetrpreter (mindkettő létezik) könnyebben kiszűri az esetleges hibákat. (pl. nem egyezik a megadott és a kikövetkeztetett típus.)

Láthatóság és hatáskör

A láthatóság és hatáskör fogalmai meglehetősen intuitívan működnek a Haskell esetében, azaz egy függvény változói a függvényre nézve lokálisak, hatáskörük kiterjed a belőlük hívott függvényekre, de a hívott függvényen belül nem láthatók. A függvények adta természetes szabályozás mellett a Haskellben van még két mechanizmus, amellyel a láthatóságot és hatáskört befolyásolni lehet. Ezek a let kifejezések és where klózok.

Hatáskör

A hatáskör a programnak azon része, amelyben a definíciók (pl.: függvény, osztály, makró, típus definíció) a bevezetett tulajdonságokkal (pl.: függvény név, osztály név, osztályváltozó, típuskonstruktor) értelmezve vannak. Két típusa van: lokális (érvényessége, láthatósága egy adott programrészre terjed ki) és globális hatáskör (mindenhonnan elérhető).
Hatásköröket csak a program megadott pontjain szabad bevezetni. Funkcionális nyelvekben jellemzően lokális deklarációk a program szövegében azelőtt vannak elhelyezve, mielőtt egy adott kifejezés használná őket (kedvező alulról felfelé típusú építkezéshez (bottom-up)).
A másik lehetőség a margószabály (off-side rule). Ez a bal oldali margó szélességének változtatása az összetartozó kifejezések csoportosításának azonosítására és deklarációk hatáskörének korlátozására (kedvező felülről lefelé típusú építkezéshez (top-down)). Blokkszerkezet kialakítását eredményezi, mely többek között átláthatóbb kódot biztosít.

Kifejezések

Egy let kifejezéssel tulajdonképpen egy beágyazott blokk hozható létre a függvényen belül, lokális változókkal. A where klózok ennek nagyjából ellenkezői, mivel több, amúgy lokális változót lehet velük összefogni. (Lásd case kifejezések - majd a vezérlőszerkezeteknél.)
Kifejezések
Ahogy kétféle változó van, úgy kétféle kifejezés is: típuskifejezés és "normális" kifejezés. A típuskifejezések végeredménye egy típus, a "normálisaké" egy érték - az érték lehet persze függvény is.
A típuskifejezéseket új típusok létrehozásakor, illetve függvények típusának megadásakor használjuk. A típuskifejezések alakja nagyjából a matematikai jelölésekkel egyezik meg, csak a Curry-féle jelölésrendszert kell alkalmazni.
A "normális" kifejezések működésükben nem térnek el jelentősen a funkcionális nyelvek kifejezéseitől (azaz szövegszerű behelyettesítés történik), ám kiértékelésük a lambda-kalkulus lusta kiértékeléséhez hasonló módszerrel történik. Ennek kellemes következménye, hogy mindent csak akkor értékel ki, ha tényleg szükség van rá, ezért nyugodtan írhatók például végtelen listák. Hátrány viszont, hogy a kiértékelés során egy, már kiértékelt kifejezést soha nem értékel ki újra (ami persze bizonyos értelemben előny), ezért ha egy nagy méretű tömb egyetlen pozíción változik meg, akkor az már kétszer fog szerepelni a kifejezésben, ami igen sok tárat foglalhat.
Általában kif :: T azt jelenti, hogy a kif kifejezésnek T a típusa..

Néhány egyszerű példa normális- és típus-kifejezésekre

-- Elemi kifejezések: 42 :: Integer 'a' :: Char True :: Bool

-- Struktúrált kifejezések: [1,2,3] :: [Integer] -- egész számok listája ('b',4) :: (Char,Integer) -- egy karakterből és egy egész számból álló pár