Funkcionális nyelvek (egyetemi jegyzet) Páli Gábor János

Méret: px
Mutatás kezdődik a ... oldaltól:

Download "Funkcionális nyelvek (egyetemi jegyzet) Páli Gábor János"

Átírás

1 Funkcionális nyelvek (egyetemi jegyzet) Páli Gábor János Budapest, 2016

2 Tartalomjegyzék 1. Rövid áttekintés Bevezetés Elágazások függvényekben Programozás listákkal A rekurzió Rekurzió listák felett: hajtogatás Függvények függvényei Részlegesen alkalmazott függvények Típusok λ-függvények Függvények kompozíciója Listák mint halmazok Lokális definíciók Interakció a külvilággal Összefoglalás Típusok Bevezetés Nevesített típusok Származtatott típusok Algebrai adattípusok Típusok összeadása Típusok szorzása Rekurzív típusok Műveletek algebrai típusok elemeivel Struktúraszerű használat Példák Üres értékek Fajták Típusosztályok Típusosztályok mint szótárak i

3 Osztályok definíciója Példányok definíciója Többértelmű nevek Átfedő példányok Típuskonstruktor-osztályok Összefoglalás A. Magyar-angol szótár 70 B. A Glasgow Haskell Compiler 73 B.1. Haskell Platform B.2. Nyelvi kiterjesztések B.2.1. A kiterjesztések engedélyezése és tiltása B.2.2. A jegyezetben alkalmazott kiterjesztések ii

4 1. fejezet Rövid áttekintés Ebben a fejezetben szeretnénk egy rövid áttekintést adni a tisztán funkcionális programozás alapvető fogalmairól. A téma mélysége és a könnyű olvashatóság fenntartása miatt itt most szándékosan nem törekedtünk a teljes részletességre. Ezért a most következő összefoglalás egyaránt alkalmas lehet arra, hogy adjon egy átfogó, vázlatos képet a témával elsőként találkozóknak, illetve mindazok számára, akik korábban már foglalkoztak vele, de szeretnék ismereteiket újra feleleveníteni. A későbbi fejezetekben az itt említett fogalmakat, megoldásokat újra elő fogjuk venni és majd kimerítőbben tanulmányozzuk Bevezetés A funkcionális programozás a deklaratív programozási paradigma egyik ága. Ekkor programjainkat mint függvény- és típusdefiníciók vegyes sorozatát adjuk meg. Ezek a definíciók aztán dominók sorozatához hasonlóan gyakran egy hosszú láncot alkotnak, melyet az egyik végéről meglökve a programunk végül lefut, ahogy az egymásra támaszkodó elemek eldőltik egymást. Ez a folyamat egészen addig tart, amíg akad az, olykor sokfelé ágazó, láncban ledönthető dominó. A funkcionális nyelvi programok esetében a lánc eldőlthető végét start kifejezésnek nevezzük, ez lesz lényegében a főprogramunk. A dominók eldőlése a definíciók, legtöbbször függvények értékének meghatározását, kiértékelését jelenti, és amikor egy összes ledönthető dominó végül eldőlt, megkapjuk a programunk végeredményét. Azonban érdemes megjegyezni, hogy a funkcionális programok számos tekintetben eltérnek a dominók sorozatától, gyakran képesek a valós világban lehetetlen trükköket végrehajtani. Például bizonyos elemeknek neveket adhatunk, amelyekre később minden olyan helyről tetszőleges mennyiségben 1

5 hivatkozhatunk, ahova beilleszthetőek anélkül, hogy több példányt gyártanánk belőlük. Vagy készíthetünk olyan sorozatot, ahol a dominók egy része újra feláll, és ezzel ismét eldönthetővé válnak. Ezáltal kapunk egy olyan sorozatot, ahol a dominók sosem fognak véglegesen eldőlni. Ez utóbbiak felelnek meg a végtelen sokáig futó programoknak. Másrészt a funkcionális programokban, ellentétben a népszerűbb, ún. imperatív programozási nyelvi programokkal, a szerző nem azt írja le, hogy az egyes részek pontosan mikor és milyen sorrendben dőljenek el. Helyette mindössze csak szabályokat ad meg erre vonatkozóan, de a tényleges folyamatot már nem irányítja közvetlenül. Ezért nevezzük tehát ezt a programozási stílust deklaratív, vagy leíró jellegű programozásnak. A deklaratív gondolkodási mód a fentiek révén nagy szabadságot ad a programozónak, amelyek segíti abban, hogy a megoldandó problémákat egy viszonylag absztrakt és matematikai oldaláról fogalmazza meg, egyfajta képletek, összefüggések alkalmazásával. Ezek így gyakran hozzájárulnak ahhoz, hogy a megoldásban kialakuljon egy rendszer, és hogy a fejlesztés során ne vesszünk el olyan könnyen a részletekben. Maga a képletszerű megfogalmazás egyébként rögvest függvénydefiníciók formájában jelenik meg, például így: negate x = 0 - x Ez a függvény egy szám előjelét fordítja meg úgy, hogy kivonja nullából. A neve annak angol nyelvű elnevezéséből fakadóan most negate, valamint egyetlen paramétere van, ez az x. A függvény nevét és paraméterét annak definíciójától, vagyis törzsétől egy = (egyenlőségjel) választja el, így ezzel lényegében egy egyenletet kapunk. Ezeket az egyenleteket fogjuk arra felhasználni, hogy eljussunk a programunk végeredményéhez. Ennek során tulajdonképpen nem kell mást csinálnunk, mint helyettesítenünk az egyenlet bal oldalán szereplő programrészletet annak jobb oldalán szereplő megfelelőjével úgy, hogy közben értéket adunk a paramétereknek. Ekkor azt is állíthatjuk, hogy a függvényünk eredménye csak és kizárólag annak bemenetétől függ, ilyen függvényeket szokhattunk meg a matematikában is. Ezeket tiszta függvényeknek nevezzük, ezek következetes alkalmazásából származik a funkcionális programozás egyik ága, a tisztán funkcionális programozás. Az iménti függvénydefiníciót úgy tudjuk felhasználni, ha elhelyezzük egy szöveges állományba, amelyet most nevezzük úgy, hogy Tutorial.hs. A.hs kiterjesztés utal arra, hogy ez egy Haskell nyelvű forrásprogram. Ezt például a Glasgow Haskell Compiler (GHC) interaktív felületén keresztül tudjuk megszólítani, ha betöltjük értelmezésre a ghci nevű programba. Windows 2

6 rendszerek esetében ehhez elegendő csak duplán kattintani az állomány nevére. Így a következő eredményt kell kapnunk: $ ghci Tutorial.hs GHCi, version : :? for help [1 of 1] Compiling Main ( Tutorial.hs, interpreted ) Ok, modules loaded: Main. A GHC telepítéséről a B. függelékben olvashatunk. Miután az állomány sikeresen betöltésre került, az értelmező lehetővé teszi számunkra, hogy egyenként hivatkozzunk az általunk definiált függvényekre, vagy akár kombináljuk ezeket. Az egész működését úgy kell elképzelünk, mint egy programozható számológépet, ahol kifejezéseket tudunk kiértékelni, és ehhez újabb és újabb függvényeket készíthetünk. A program a kiértékelendő kifejezéseket a sikeres betöltést követően egy Main*> kezdetű sorban, egy promptban várja. Itt maga a Main annak a függvénytárnak, modulnak a neve, amely a saját definícióinkat tartalmazza. Mivel nem adtunk neki külön nevet a forráskódban, az értelmező alapértelmezés szerint így nevezi el, függetlenül az állomány nevétől. A továbbiakban az értelmező promptját egyszerűen csak úgy jelöljük, hogy GHCi>. GHCi> negate 1-1 GHCi> negate (negate 1) 1 GHCi> negate -1 <interactive>:3:1: Non type-variable argument in the constraint: Num (a -> a) (Use FlexibleContexts to permit this) When checking that it has the inferred type it :: forall a. (Num a, Num (a -> a)) => a -> a Ezt az értelmezővel folytatott párbeszédet Read-Eval-Print (mint beolvasni, kiértékelni, kiírni, röviden REP) ciklusnak hívják. Először az értelmező beolvassa és értelmezi a bemenetként kapott kifejezést, majd, amennyiben ez sikeres volt, kiértékeli, vagyis kiszámolja az eredményét, melyet végül kiír. Sajnos, ahogy a fenti példában látható, az utolsó kifejezés valamiért nem volt elfogadható. Ez arra mutat egy példát, amikor a fordító valamilyen oknál fogva nem képes megérteni a beolvasott szöveget, miközben az a nyelv helyesírási, másnéven szintaktikai szabályainak látszólag teljesen megfelel. A fordító ugyanis nem egyszerűen csak ezen szabályok szerint ellenőrzi a bemenetet, hanem elvégez egy ún. típusellenőrzési lépést is, amely tulajdonképpen 3

7 a kifejezés nyelvhelyességi, azaz szemantikai vizsgálatára utal. A konkrét hiba részleteit itt most nem fejtjük ki, röviden csak annyit jegyzünk meg, hogy mindez azért számít Haskellben szemantikai hibának, mert a - (mínusz) szimbólumot egyszerre lehet a kivonás bináris, és az előjelváltás unáris operátorának tekinteni. Ezért ez a megfogalmazás kisebb fejtörést tud okozni a fordító számára, így mint ökölszabály, mindig javasolt a programokban a negatív számokat külön zárójelbe tenni: GHCi> negate (-1) 1 Az értelmező használata során arra mindig ügyelnünk kell, hogy minden esetben, amikor a programot megváltoztatjuk, azt újra be kell töltenünk. Ezt az értelmezőn belül egy paranccsal tudjuk elvégezni, ennek a neve :reload. Figyeljük meg, hogy a parancs a : (kettőspont) szimbólummal kezdődik, ezzel tudja az értelmező megkülönböztetni a feldolgozandó kifejezéseket a parancsoktól. GHCi> :reload [1 of 1] Compiling Main ( Tutorial.hs, interpreted ) Ok, modules loaded: Main. A parancs rövidítéseként azt is írhatjuk, hogy :r, illetve maga a : (üres parancs) alkalmas arra, hogy az utolsóként kiadott parancsot megismételtessük. Érdemes tudni, hogy a :? segítségével az összes elérhető parancsot mindig lekérdezhetjük Elágazások függvényekben A függvénydefiníciók sokszor azonban nem ennyire egyszerűek, mivel alkalmanként el is kell ágazniuk. Például tegyük fel, hogy készíteni szeretnénk egy olyan függvényt, amelyik egy szám abszolút értékét képes kiszámítani. Ebben az esetben a szám értékétől függően, amennyiben az negatív, előjelet váltunk vagy változatlanul hagyjuk. Ez utóbbi kapcsolatban megjegyezzük, hogy a tisztán funkcionális programok esetében az értékek nem változhatnak meg a program futása során. Vagyis egy név mindig ugyanazt a hozzárendelt értéket hivatkozza, függetlenül attól, hogy a programban merre található. Ezt hivatkozási helyfüggetlenségnek nevezzük. Továbbá ehhez kapcsolódóan azt mondjuk, hogy a programbeli változóink egyszer kapnak csak értéket. Ennek megfelelően tehát a függvényünk majd nem fogja módosítani a kapott paraméter értékét, hanem helyette egy új, de már módosított értéket fog visszaadni. 4

8 Haskell programokban elágazásokat többek közt ún. őrfeltételek hozzáadásával képezhetünk. Az őrfeltételek olyan logikai értékű kifejezések, amelyeket a függvénydefiníció bal oldalán, a függvény nevét és a paraméterlistát követően helyezhetünk el a (függőleges vonal) szimbólummal elválasztva. Ennek szemléltetéséhez most vegyük az osztási művelet egy olyan speciális változatát, ahol a számítást magát csak abban az esetben végezzük el, amikor az osztó nem egyenlő nullával: x./. y y /= 0 = x / y Ekkor a függvény törzsét (az egyenlet jobb oldalát) csak az őrfeltétel teljesülésekor fogja csak a program futtatását végző rendszer kiértékelni. Minden más esetben az adott törzs feldolgozása kimarad és a futtató rendszer folytatja a következő, teljesíthető őrfeltétellel rendelkező ágat, miközben fentről lefelé halad. Amennyiben nem adtuk meg további lehetséges törzseket, ún. függvényalternatívákat, futási idejű hiba, kivétel keletkezik. Ezt az értelmező közvetlenül meg is jeleníti, mivel ilyen esetekben nem képes választ adni a korábban feltett kérdésünkre: GHCi> 42./. 0 *** Exception: Tutorial.hs:5:3-26: Non-exhaustive patterns in function./. Ezt a matematikából kiindulva parciális függvénynek nevezzük. Ezek olyan függvények, amelyek nem minden értékhez rendelnek másikat, bizonyos pontjaikban nem értelmezettek. Ahogy láthattuk, ezek alkalmazása viszont futási hibához vezet, amely egyúttal a teljes programunk kiértékelésének leállását jelenti. Ennek okán a gyakorlatban az ilyen függvények írása nem javasolt, a későbbiekben ennek elkerülésére látni is fogunk megoldásokat. A parciális függvény ellentéte a totális függvény, amely fogalmát szintén a matematikából kölcsönöztük, ahol minden értékhez rendelünk valamit. Most adjuk meg az abs, vagyis az abszolútérték-függvény definícióját őrfeltételek használatával! Vigyázzunk azonban a tördelésre! Ugyanis ez már egy többsoros definíció lesz, ahol a fordító a behúzások alapján képes megérteni, az egyes sorok miként kapcsolódnak egymáshoz. Ezt margószabálynak hívják, amelynek lényege, hogy a hosszabb definíciókat eltörhetjük és több sorban írhatjuk. Ilyenkor az első sor után következőket mindig bentebb kell húznunk szóközökkel, és ezáltal egy margót képzünk: abs x x < 0 = negate x otherwise = x 5

9 Ebben a definícióban tehát két eltérő ágat is felfedezhetünk. Az egyik fogalmazza meg a kivételes esetekre, vagyis a negatív számokra vonatkozó szabályt, és alkalmazza rájuk a korábban már definiált negate függvényünket. A másik pedig az összes többi esetet kezeli. Ez egyben egy olyan őrfeltételre is mutat példát, amely igazából nem akadályozza meg az adott törzs kiértékelését. Ebben ugyanis valójában az otherwise konstans szerepel, amely az azonosan igaz logikai értéket fedi: GHCi> otherwise True Az eddigiek alapján megfigyelhetjük, hogy az egyes alternatívák őrfeltételeit tehát a kiértékelés során fentről lefelé vizsgáljuk, és közülük végül azt a törzset választjuk, amely először értékelődik igazra. Vegyük észre, hogy ennek megfelelően, ha az otherwise feltétel szerepel először, akkor az minden más ágnál hamabb, tőlük lényegében függetlenül válik igazzá, így azok sosem fognak szóba kerülni. Ha viszont először a kivételeket soroljuk fel, képes az összes többi esetre választ adni, egyfajta védőhálóként megakadályozza, hogy a függvény véletlenül parciálissá váljon. Haskellben létezik továbbá az imperatív nyelvekben ismert if ( ha... akkor... utasítás) megfelelője is. Ez azonban, a nyelv és paradigma jellegéből fakadóan, nem utasítás, hanem függvény. A tisztán funkcionális nyelvekben ugyanis csak és kizárólag függvények vannak, nincsenek utasítások. Emiatt a programjaink sem lesznek többek, mint hatalmas kifejezések, amelynek egyszerűen csak ki akarjuk számítani az értékét. Másrészt ennélfogva már a legkisebb kifejezések is programnak számítanak, és az értelmező a kiértékeléssel ezeket a programokat futtatja. Ennek következményeképpen, bár az if kulcsszónak számít, teljesen egy háromparaméteres függvényként kell rá gondolnunk. Ezért mindig, minden paraméterét meg kell adnunk: az elágaztatás logikai feltételét, valamint az igaz és hamis értékeknek megfelelő kifejezések. GHCi> if True then 1 else 0 1 Ezen keresztül az abs függvény így lenne megadható az if használatával: abs x = if (x < 0) then (negate x) else x Azonban az ágak számának növekedésével az őrfeltételek sokkal jobb választásnak bizonyulnak, mivel így a programjaink rövidebbek maradnak. Ezért a funkcionális nyelvi programokban inkább ezeket szoktuk alkalmazni. 6

10 1.3. Programozás listákkal Az egész számok mellett Haskellben sok más típus is használható. Például, ahogy az otherwise esetében is láthattuk előzőleg, tudunk logikai értékekkel is dolgozni. Sőt, ahogy majd később (2. fejezet) láthatjuk, a nyelv tetszőleges típus definiálását lehetővé teszi. A funkcionális programokban másik gyakran előforduló típus a lista, amelynek történelme egészen az első funkcionális nyelvig, a LISP (mint "list processing") programozási nyelvig visszanyúlik. A listák értékek egyszerű tárolóiként használhatóak. A legegyszerűbb lista az üres lista. GHCi> [] [] De ennél bonyolultabb listákat is létre tudunk hozni az elemeik felsorolásával, vesszők között felsorolva: GHCi> [1,2,3,4,5] [1,2,3,4,5] Vagy akár magát az értelmezőt is megkérhetjük, hogy magától állítsa elő ugyanezt a listát. Ehhez mindössze a felsorolás alsó és felső korlátját kell megadnunk, köztük két ponttal: GHCi> [1..5] [1,2,3,4,5] Listákat nem csak így lehet építeni. Ezeket valójában az előbb bemutatott üres lista és egy ún. építő operátor segítségével lehet készíteni, amelynek jele a : (kettőspont). A : operátornak egy listaelemre és listára van szüksége, melyekből képes egy újabb listát készíteni. Ez egy jobbasszociatív művelet, vagyis ha többször egymásba ágyazva alkalmazzuk, akkor mindig a jobb oldali példányt kell először kiértékelni. GHCi> 1 : (2 : (3 : (4 : (5 : [])))) [1,2,3,4,5] Érdemes tudni, hogy az egyszerűség kedvéért a fordító mindig ebben a formában tárolja a listákat. Az imént bemutatott többi lehetőség csupán ennek egy-egy másik felírási módja, amely a könnyebb olvashatóságot hívatott elősegíteni. Ezt nyelvi ízesítésnek szoktuk nevezni, amely egy gyakran alkalmazott technika a funkcionális nyelvek definíciójában. 7

11 A listák eredeti ábrázolási módjával azért is fontos tisztában lennünk, mert így listákat feldolgozó függvényeket is lehetőségünk nyílik írni. Erre példaként tekintsünk egy olyan függvényt, amely az == operátor (egyenlőségvizsgálat) segítségével ellenőrzi, hogy egy adott lista üres vagy sem: isempty xs = xs == [] amelyet a következőképpen próbálhatunk ki az értelmezőben: GHCi> isempty [] True GHCi> isempty [1..5] False Megjegyezzük, hogy ilyen függvényeket lehetőségünk van egy másik eszközzel, ún. mintaillesztéssel megfogalmazni. A mintaillesztés során a függvény által kapott értéket annak szerkezete szerint különböző mintákkal vetjük össze és annak alapján választjuk meg a függvény eredményét. Ezen keresztül, az őrfeltételek használatához hasonlóan, függvényalternatívák sorozatát tudjuk felsorolni, melyek mindegyikéhez egy-egy minta fog tartozni. A függvény értékének kiszámítása során ezeket a mintákat fogjuk azok megadásának sorrendjében (fentről lefelé) megpróbálni illeszteni a függvény paramétereire, és a kiértékelést azzal a függvénytörzssel folytatjuk, ahol azok a szerkezeti szabályok szerint megfelelnek. Az összes többi törzs ekkor feldolgozatlan marad. Például annak eldöntése, hogy egy lista üres vagy sem, ezzel a módszerrel a következő módon fogalmazható meg: null [] = True null _ = False Itt az első alternatíva csak és kizárólag az üres lista konstans esetén fog illeszkedni, és ekkor a függvény a True (igaz) értéket veszi fel. Az összes többi lehetőséget egy ún. joker mintával fedjük le, amely tetszőleges értékre illeszkedik. Ennek kapcsán hozzátesszük, hogy a joker minta alkalmazásakor az adott paraméter értékehez sem tudunk hozzáférni (hiszen nem neveztük el), ezért ilyet akkor írunk, ha attól függetlenül akarjuk képezni a függvény értékét. Emiatt a joker mintát úgy is nevezhetjük, hogy névtelen változó. Ennél összetettebb listákat úgy tudunk feldolgozni függvényekkel, ha a listák felépítésének inverzében gondolkodunk. Vagyis a : szimbólummal most nem egy elemet és egy listát építünk össze listává, hanem egy listát bontunk fel ennek segítségével egy elemre és egy listára. Ezeket, a szintén LISP-től 8

12 származó örökség részeként, a lista fejének és törzsének nevezzük. A nekik megfelelő függvények már csak mintaillesztés segítségével fogalmazhatóak meg: head (x:_) = x head _ = error "head: empty list" tail (_:xs) = xs tail _ = error "tail: empty list" Innen talán jobban kiderül, hogy a mintaillesztés valójában kicsivel több, mint mezei egyenlőségvizsgálat. Észrevehetjük ugyanis, hogy egy minta tartalmazhat lyukakat, amelyeket változónevekkel tudunk lefedni. Az illesztés során ezeket a lyukakat fogjuk majd kitölteni az adott paraméter mintának megfelelő, egyező részeivel, melyekre aztán így később a függvény törzsében akár külön-külön is hivatkozni tudunk. Mellette azt is megfigyelhetük, hogy a listákra vonatkozó mintákat zárójelbe kellett tennünk, mivel ott egyetlen értéket akarunk több részre felbontani. A head definíciójában egy lista csak akkor fog illeszkedni az első alternatívához tartozó mintára, amennyiben azt annak idején a : szimbólummal hoztuk létre. Minden más esetben egy hibaüzenetet hozunk létre, amely lényegében a [], azaz az üres lista esete. Erre azért van szükség, mert ha az üres listának nincs feje, vagyis nem tudunk belőle elölről leválasztani elemet. Így a head emiatt egy parciális függvény lesz. Ugyanez a gondolatmenet érvényes a tail esetében is. GHCi> head [] *** Exception: head: empty list GHCi> head [1..5] 1 GHCi> tail [1..5] [2,3,4,5] 1.4. A rekurzió A listák esetében gyakorta előfordul, hogy a függvénnyel a teljes listát végig kell járnunk. Például elegendő csak arra gondolnunk, amikor el akarjuk dönteni, hogy két lista egyenlő-e. Ilyenkor, mivel nem tudjuk pontosan a program írásakor, az egyes listák milyen hosszúak lehetnek, valamilyen, az egyes elemek esetében azonos módon elvégezhető, általánosított lépéssorozat ismétlésére, iterálására van szükségünk. 9

13 Funkcionális nyelvekben erre a rekurzió fogalmát használják fel. Egy függvényt rekurzívnak nevezünk minden olyan esetben, amikor a definíciójában saját magára hivatkozik. Ezért gyakran a rekurziót úgy is szokták tréfásan definiálni, hogy Rekurzió: ld. rekurzió. A tisztán funkcionális nyelvekben nagyon óvatosan kell bánnunk az imperatív nyelvekből ismert, teljesen ártatlan megoldásokkal, mint amilyen a következő is: x = x + 1 Ha imperatív módon tekintünk a fenti egyenletre, akkor ezt úgy kellene értelmeznük, mint az x értékének növelését eggyel. Ez viszont a Haskell működési elvei szerint egy végtelen rekurzió eredményez, amely kiértékelése során az értelmező sosem lesz képes befejezni az eredmény meghatározását. Ez azért történik így, mert ebben az esetben definiálni akarjuk az x függvényt, amely tulajdonképpen egy konstans (mivel nincs paramétere, tehát mindig ugyanazt az értéket fogja képviselni), és ennek meghatározásához szükségünk lenne annak korábbi értékére. Ezt az értéket viszont éppen akkor szeretnénk kiszámítani, amely utána folyamatosan, a végtelenségig magára hivatkozik. Az imperatív nyelvekben ez a szerkezet azért működőképes, mert az x értékének van egy állapota, és amikor a fenti értékadást értelmezzük, akkor annak bal oldalán mindig az új, a jobb oldalán pedig a régi állapotáról beszélünk. Tisztán funkcionális nyelvekben azonban a hivatkozási helyfüggetlenség miatt végig ugyanarról értékről beszélünk, innen adódik az eltérő viselkedés. Ha valamiért egy ilyen végtelen ciklusba keverednénk a számítások során, a Ctrl+C billentyűkombinációval ezeket bármikor megszakíthatjuk: GHCi> x ^CInterrupted. Ennek ellenére, meglepő módon, Haskellben az ilyen végtelen eredményt gyártó függvények esetenként lehetnek hasznosak, mindössze csak a megfelelő típusban kell gondolkodnunk. Például tekintsünk az alábbi függvény definícióját: repeat x = x : (repeat x) Ezt a következő módon tudjuk használni az értelmezőn keresztül: GHCi> repeat 1 [1,1,1,1,1,1,1,1,1,1,1^CInterrupted. 10

14 Habár láthattuk, hogy a függvény kiszámítása ebben az esetben sem fog önmagától befejeződni, az értelmező mégis képes volt valamilyen köztes eredményt, egyesek véget nem érő folyamát, megjeleníteni. Ennek megértéséhez észre kell vennünk, hogy a repeat függvény definícióját nem feltétlenül úgy kell olvasnunk, ahogy azt az imperatív nyelvek esetében megszokhattuk. Annak megfelelően elsőként ugyanis a zárójeles részt, a repeat x részkifejezést kellene kiszámítanunk, és ehhez kellene a : alkalmazásán keresztül az x értékéből még egy elemet az így elkészített lista elé fűzni. Ezt a kiértélési módszert mohónak nevezzük, ahol a függvények alkalmazásához először mindig ki akarjuk számítani a paraméterek értékeit, és csak utána velük a függvény értékét. Azonban létezik egy másik megközelítési mód, ahol elsőként mindig a függvényt számítjuk ki, és a paramétereivel kizárólag csak akkor foglalkozunk, amennyiben arra szükségünk van. Emiatt elképzelhető az is, hogy egyáltalán nem fogjuk valamelyik paramétert kiértékelni. Ezt lusta kiértékelésnek nevezzük, és Haskellben is ezt alkalmazzák. Ennek megfelelően a repeat értékének kiszámítása során először a felsőbb szinten szereplő operátort, vagyis a : műveletét végezzük el először, és így a még el nem készült lista elejére illesztjük vele az x értékét. Ezt folytatjuk a repeat rekurzív kiszámításával, amellyel mögé kerül egy másik x érték, és az egész folyamat egészen a végtelenségig halad. A lustaságnak és annak köszönhetően, hogy a részkifejezéseket így csak akkor értékeljük ki, amennyiben ténylegesen szükségünk van az értékükre, az alábbi kifejezés viszont már véges idő alatt kiszámítható lesz: GHCi> head (repeat 1) 1 A kapott eredmény fenti gondolatmenetet követve teljesen logikusnak tűnik: miért bontanánk ki a teljes listát, miközben a válaszadáshoz elegendő csak az első elemének meghatározása? A lustaságnak köszönhetően Haskellben lehetőségünk van végtelen adatszerkezetekkel dolgozni, amely az algoritmusok leírását is meglepően elegánssá és tömörré tudja tenni. Fontos megjegyeznünk, hogy nem minden funkcionális nyelv esetében igaz, mivel a mohó kiértékelés azokban is sokáig az uralkodó kiértékelési stratégia volt, tehát például a LISP is ilyen. Természetesen a repeat függvény a véges változatát is el tudjuk készíteni, ha korlátozzuk a listába illeszthető elemek számát. Tisztán funkcionális programozás esetében, mivel nincsenek állapottal rendelkező nevek, vagyis a hagyományos értelemben vett programváltozók, ezt úgy tudjuk megoldani, ha felveszük a függvénynek egy újabb paramétert. Ez a paraméter egy 11

15 számláló szerepét fogja játszani, amelyet a korlát adott értékétől visszafele indulva lépésenkét mindig eggyel csökkentünk egészen addig, amíg az pozitív. Így lényegében két esetet fogunk kapni. Egy ún. induktív esetet, amikor a rekurzív hivatkozással megadjuk, hogy miként építjük a listát, miközben csökkentjük a számlálót, és egy ún. alapesetet, amikor a függvény rekurzió segítsége nélkül képes lesz közvetlenül meghatározni az értékét. Az induktív eset felel meg a ciklus lépéseinek, magjának újbóli végrehajtásának, az alapeset pedig a ciklusból kilépés, vagyis az ismétlés megállításának feltételeit írja le. Ezeket az eseteket függvényalternatívák felhasználásával adhatjuk meg. Így a repeat véges változata, a replicate a következőképpen áll elő: replicate n x n <= 0 = [] otherwise = x : (replicate (n - 1) x) Megfigyelhető, hogy a replicate első paramétere, vagyis a számláló, rekurzívan mindig az előzőnél eggyel kisebb értékkel hívódik meg. Ellenkező esetben a rekurzió sosem fejeződne be. Ezért fontos törekednünk arra, hogy az induktív esetek megfogalmazása során mindig igyekezzünk elérni az alapesetekben leírt leállási feltételeket. Ezt úgy tehetjük meg, hogy a rekurzív hívás során legalább az egyik paramétert megváltoztatjuk. Ez a replicate tehát esetében azt jelenti, hogy a számláló értéke lépésenként csökkent és az ismétlés megáll, amikor nullára vagy az alá érünk. GHCi> replicate 0 1 [] GHCi> replicate 3 1 [1,1,1] GHCi> replicate (-3) 1 [] Nem csak számok, de más típusú értékek is csökkenthetőek, ezáltal rekurzív stílusban feldolgozhatóak. Ilyenek többek között a listák, ahol csupán a lista törzsének a továbbadása elegendő lehet egy alapeset eléréséhez, amely ekkor általában az üres lista. Emiatt listák esetében a törzs kiszámítása lényegében az eggyel csökkentésnek, az üres lista pedig a nulla konstansnak feleltethető meg. Mindezekre példaként tekintsünk most a take függvény definícióját, amelynek az a feladata, hogy egy lista elejéről adott számú elemet adjon vissza, amennyiben ez lehetséges. Ha nem, akkor adja vissza az eredeti listát változatlanul. 12

16 take _ [] = [] take n _ n <= 0 = [] take n (x:xs) = x : take (n - 1) xs Észrevehetjük, hogy ebben a definícióban mintaillesztést és őrfeltételeket is alkalmaztunk vegyesen, így fejeztünk ki két lehetséges alapesetet. Az első sor értelmében ha a feldolgozandó lista üres, akkor az első paraméter (a számláló) értékétől függetlenül egyszerűen csak adjunk vissza egy üres listát. A második sor szerint ha a kivenni kívánt elemek számát jelző számláló már nem pozitív, akkor ismét adjunk vissza üres listát, hiszen már nem kell belőle többet kivennünk. Végezetül a harmadik sorban azt olvashatjuk, hogy minden más esetben vegyük a lista első elemét és illesszük hozzá a : operátorral ahhoz a listához, amelyet úgy nyerünk, hogy egy eggyel rövidebben listából veszünk ki, a take rekurzív alkalmazásával, eggyel kevesebb elemet. Ehhez az esethez a mintaillesztés és az őrfeltételek viselkedésének megfelelően mindig akkor jutunk, ha az előtte szereplő alapesetek feltételei közül egyik sem teljesült még. A take függvény is lusta lesz, így képes akár végtelen listákkal is dolgozni. Például olyanokkal, amelyeket a repeat felhasználásával állítottunk korábban elő: GHCi> take 3 (repeat 1) [1,1,1] Ennek mikéntjének pontosabb megértéséhez tekintsük át, miként is fog az adott kifejezés kiértékelése végbemenni: take 3 (repeat 1) < illeszkedés a take 3. sorára, ahol n = 3, x = 1, xs = repeat 1 > 1 : take (3-1) (repeat 1) 1 : take 2 (repeat 1) < illeszkedés a take 3. sorára, ahol n = 2, x = 1, xs = repeat 1 > 1 : 1 : take (2-1) (repeat 1) 1 : 1 : take 1 (repeat 1) < illeszkedés a take 3. sorára, ahol n = 1, x = 1, xs = repeat 1 > 1 : 1 : 1 : take (1-1) (repeat 1) 1 : 1 : 1 : take 0 (repeat 1)

17 < illeszkedés a take 2. sorára, ahol n = 0 > 1 : 1 : 1 : [] [1,1,1] Emellett még az is tetten érhető, hogy a replicate tulajdonképpen a take és a repeat kompozíciójaként is megfogalmazható, amely remekül összeegyeztethető a moduláris programozás elveivel: replicate n x = take n (repeat x) 1.5. Rekurzió listák felett: hajtogatás A listák felett szervezett rekurzió kapcsán érdemes foglalkozni valamennyit a mögötte megbúvó sémával. Ez egy jól általánosítható séma, amelyet hajtogatásnak nevezzük. Ez arról szól, hogy folyamatosan vesszük egy lista elemeit és belőlük egy kétparaméteres függvény felhasználásával lépésenként egy görgetett, hajtogatott értéket építünk fel, amely aztán az így képzett számítás végeredménye lesz. Az elemek bejárásának, így a hajtogatásnak az iránya lehet balról jobbra: vagy jobbról balra: (... ((((z x 0 ) x 1 ) x 2 ) x 3 )...) x n x 0 (x 1 (x 2 (x 3 (... (x n z)...)))) ahol a kétparaméteres függvény, az x 0, x 1,..., x n értékek a összehajtogatni kívánt lista adott indexű elemei, valamint a z a hajtogatás során képzett, göngyölt eredmény kezdőértéke. A függvénynek attól függően, hogy balról vagy jobbra hajtogatunk vele, bal- illetve jobbasszociatívnak kell lennie. Értelemszerűen asszociatív függvények mind a két esetben alkalmazhatóak. Például tekintsük az elemek összeadását! Ekkor az operátor az összeadás (+) lesz, a hozzá tartozó kezdőérték a 0, és a hajtogatás során kiszámított érték pedig a listában szereplő elemek összege. Annak alapján, amit eddig láthattunk a listák felett értelmezett rekurzióról, nem is annyira nehéz megadni egy ilyen függvény definícióját: sum [] = 0 sum (x:xs) = x + sum xs Ha az egyes szabályokat valamilyen lista esetében értelmezni kezdjük, akkor láthatjuk, hogy a függvény alkalmazásával a következő transzformációt végezzük el: 14

18 sum [1,2,3] --> 1 + sum [2,3] --> 1 + (2 + sum [3]) --> 1 + (2 + (3 + sum [])) --> 1 + (2 + (3 + 0)) A funkcionális programozásban ez a séma megfogható egy alkalmas függvényfajtával, amelyet magasabbrendű függvényeknek nevezünk. Magasabbrendűnek nevezünk minden olyan függvényt, amely vagy függvényt kap paraméterül, vagy pedig függvényt hoz létre eredményként. Ez a lehetőség abból származik, hogy funkcionális nyelveken a függvények az értékekhez, például számokhoz hasonlóan feldolgozhatóak és képezhetőek. Itt és most csak az első esetet használjuk ki, vagyis amikor a függvényünk egy másik függvényt kap paraméterül, de később majd kitérünk a másik esetből következő lehetőségekre is. Kezdésképpen azonban még ne az imént megismert sémát próbáljuk meg ezen a módon kifejezni, hanem helyette tekintsünk egy egyszerű, de érdekes példát a magasabbrendű függvényekre, a map függvényt. Ez a függvény egy függvényt és egy listát kap paraméterül, majd visszaad egy olyan listát, ahol a lista összes elemére alkalmazza a függvényt. Az angol matematikai szaknyelvben ugyanis a "map" leképezést jelent, vagyis amikor vesszük egy halmaz összes elemét, és azt teljes egészében egy másik halmazba képezzük át. GHCi> map negate [1,-1,2,-2,3,-3] [-1,1,-2,2,-3,3] Megfigyelhetjük, hogy a negate függvényt látszólag mindenféle paraméter nélkül hívtuk meg. Ez annak a következménye, hogy a függvényt értékként fogtuk meg, és ilyenkor csak a nevére van szükségünk. Minden mást meg fog kapni a map függvénytől, ahogy annak a definíciójából is kiderül: map _ [] = [] map f (x:xs) = (f x) : (map f xs) Látható tehát, hogy a negate itt az f paraméter értékeként jelenik, és a definícióban ennek adjuk át folyamatosan a listában egymás után kivett értékeket. A függvényt egyszerűen csak a map egyik paramétereként vettük fel és úgy használjuk, mintha egy korábban már definiált függvényről lenne szó. 15

19 1.6. Függvények függvényei Most, miután láttuk, hogy miként lehet rekurzív és magasabbrendű függvényeket készíteni, fogalmazzuk meg a korábban említett hajtogatási sémát! Az egyszerűség kedvéért itt csak a jobbról hajtogatással, vagyis a foldr ("fold right") függvény definíciójával foglalkozunk, de ehhez hasonlóan a balra hajtogatás, vagyis a foldl ("fold left") is megadható: foldr _ z [] = z foldr f z (x:xs) = f x (foldr f z xs) Tekintsük a definíció egyes részeit! Amikor a lista üres, a függvény értéke legyen a hajtogatás eredményének kezdőértéke, mivel ebben az esetben befejeződik a rekurzió. A listában tárolt számok összegzésénél ez lényegében azt jelentette, hogy az üres listához az összeadás egységelemét, a nullát rendeltük. Amennyiben a lista nem üres, vegyük a lista soron következő, vagyis első elemét és a függvény felhasználásával azt kombináljuk össze azzal az értékkel, amelyet úgy nyertünk, hogy a lista fennmaradó részére (törzsére) alkalmaztuk a hajtogatást (jobbasszociatív) módon. Ezzel a sémával most már képesek vagyunk a sum függvényt akár egyetlen sorban összefoglalhatóan leírni: sum xs = foldr (+) 0 xs Itt láthatjuk, hogy a számok összegzéséhez a + függvényt és a 0 kezdőértéket adtuk át a foldr függvénynek. Nem nehéz ellenőrizni, hogy ha ezeket a paramétereket közvetlenül behelyettesítjük a foldr definíciójába, akkor visszakapjuk belőle a sum definícióját. Ezért is tekinthetőek a magasabbrendű függvények a hagyományos függvényeknél erősebbeknek: az általuk megfogalmazott függvényosztályban minden függvény kifejezhetően csupán annyival, hogy a megfelelő törzset helyettesítjük a definíciójukba. A fenti példában a + műveletet ismét paraméterek nélkül adtuk át. Illetve, mivel operátor, és ezért a nyelv helyesírási szabályai szerint szimbólumokból kell, hogy álljon, zárójelbe is kellett tennünk. Természetesen a foldr függvénynek bármilyen más függvény is átadható, akár olyanok is, amelyeket mi magunk írtunk. Velük szemben az egyedüli igazi követelmény, hogy a típusuk megfelelő legyen. Noha a típusok kérdéskörét eddig ügyesen sikerült elkerülnünk, tagadhatatlan, hogy a Haskell programok írásának ez egy másik létfontosságú, azonban sokszor láthatatlan része. Haskellben minden függvénynek van típusa annak ellenére, hogy ezek közül eddig egyetlen egyet sem említettünk. Az értelmezőben az egyes kifejezések típusát a :type (vagy röviden :t) paranccsal kérdezhetjük le. Nézzük meg például meg, hogy mi a foldr típusa: 16

20 GHCi> :type foldr foldr :: (a -> b -> b) -> b -> [a] -> b A válasz megértéséhez elsőként megjegyezzük, hogy Haskellben a nevekhez a típusra vonatkozó információt a :: (dupla kettőspont) szimbólummal kapcsoljuk. Továbbá a függvények típusaiban a -> (nyíl) szimbólum szerepel, amely lényegében egy típusok felett értelmezett operátor, amelyet arra használunk, hogy leírjuk vele a függvény értelmezési tartománya és annak értékkészlete közötti összefüggést: f :: A -> B Ekkor tehát az f egy olyan függvény lesz, amelyik az A típusból (mint értelmezési tartományból) a B típusba (mint értékkészletbe) képez. Többparaméteres függvények esetében alkalmazhatnánk a matematikában megszokott jelölést, vagyis az értelmezési tartományok Descartes-szorzatát. Például úgy, hogy a létezik egy másik típusszintű operátor, az x, amely két típus szorzatát írja le: f :: A x B -> C Ilyen lehetőség létezik Haskellben is, azonban ezt a, (vessző) operátorral jelöljük: f :: (A, B) -> C Azonban technikai okból, melyekről majd a későbbiekben lesz részletesebben szó, a nyelv tervezői ehelyett mindenhol csak a nyíl operátor alkalmazása mellett döntöttek: f :: A -> B -> C Ezáltal a függvények típusát a következő ökölszabály szerint lehet könnyen értelmezni. A nyilakkal elválasztott részek közül az első (n 1) darab tag a rendre paraméterek típusainak feleltethető meg, míg az utolsó, vagyis n. tag a függvény értékének típusát adja meg. Ennek a magyarázatnak megfelelően kiderül, hogy a foldr függvénynek három paramétere van: a -> b -> b b [a] 17

21 Itt a függvények típusa mellett egy másik típusoperátort is felfedezhetünk, ez a [] avagy a lista szimbóluma. Ez szintén egy típusok felett értelmezett függvény, azonban ennek csak egyetlen paramétere van, a listában szereplő elemek típusa. Ez tehát, hasonlóan a -> viselkedéséhez, egy típusból egy másik típust képez, az adott típusú elemeket tartalmazó lista típusát. A rövid alapozás után most menjünk egyesével végig a foldr paraméterein: az első egy függvény, a második valamilyen érték, a harmadik pedig egy lista. Ami azonban feltűnő lehet, hogy nem látunk bennük egyetlen konkrét típust sem, helyettük csak az a és b betűk szerepelnek. Ezek a típusokban szereplő változók, vagyis típusváltozók, amelyeken keresztül az ún. parametrikus polimorfizmus jelenik meg. Ez az jelenti, hogy a foldr függvény nem csak adott típusokra alkalmazható, hanem automatikusan képes szinte tetszőleges típusú értékekkel dolgozni. A változókat arra használjuk a típus leírásában, hogy az egyes paraméterek, illetve a visszatérési érték egymáshoz való logikai viszonyait kifejezzük. Így, ha ezeket a típusváltozókat tényleges típusokkal helyettesítjük, ennek az egyébként absztrakt típusnak kapjuk meg végtelen sok konkretizált változatát. Például tekintsük azt az esetet, amikor az a értéke Integer, a b értéke pedig Bool, ahol az Integer egész számot, a Bool logikai értéket jelent: foldr :: (Integer -> Bool -> Bool) -> Bool -> [Integer] -> Bool Azonban a helyettesítéskkel kapcsolatban van egy nagyon fontos szabály. Az egyes típusváltozók értékét mindig csak ugyanarra a típusra cserélhetjük. Tehát a foldr alábbi konkretizálása helytelen, ezzel a paraméterezéssel már nem használható: foldr :: (Bool -> Bool -> Bool) -> Integer -> [Integer] -> Integer Az eddigi függvényeink típusát ún. típuskikövetkeztetésen keresztül kaptuk meg, ezért nem volt szükséges nekünk kitalálni és megadni. A típuskikövetkeztetés egy algoritmus, amely mindig megpróbálja a függvény legáltalánosabb, vagy más néven principális típusát meghatározni. A foldr esetében az imént megadott, típusváltozókat tartalmazó típus az összes lehetséges közül a legáltalánosabb, mivel a függvény leírása során: Mivel a függvény harmadik paraméterére egyszer az üres listát ([]), máskor pedig az : szimbólumon keresztül a listák felbontását lehetővé tevő mintát illesztettük, feltételezhető, hogy ez valamilyen értékeket tartalmazó, vagyis egy a típusú lista. 18

22 A második paraméterrel nem csináltunk semmi különlegeset, ezért nem lehetünk biztosak benne, hogy a listákban található értékek típusával azonos típusú lesz, így egy új, eddig nem használt típusváltozót rendelünk hozzá, ez legyen a b. Végezetül, az első paramétert úgy használtuk, mint egy függvényt, amely a listából kivett (a típusú) elemet kapja első paramétereként, majd a a foldr rekurzív hívásával számolt (b típusú) értéket második parmétereként és ugyanolyan típusút is ad vissza, annak típusának végül annak kell lennie, hogy a -> b -> b. Ez utóbbira bizonyítékot a függvény definíciójának első sorában láthatunk, amikor a második paramétert változtatás nélkül visszaadjuk, amelyről már tudjuk, hogy b típusú. Amikor a fordító nem képes ez egy ehhoz hasonló gondolatmenettel magától kikövetkeztetni a típust, hibát jelez és nem fordítja le a programunkat. Ezért ezt a folyamatot típusellenőrzésnek is nevezik. A típusok kikövetkeztetése nem csak a típusokra vonatkozó információk megadásától mentesít minket, hanem arra is alkalmas, hogy ellenőrizzük az adott definíció értelmét. Tehát ez lényegében a programunk egyfajta szemantikai értelmezéseként is szolgál. Képzeljük el a foldr definíciójának egy látszólag helyes, viszont valójában egy elrontott változatát: foldr _ z [] = z foldr f z (x:xs) = f x (foldr z f xs) Ha ezt a programot most be akarnánk tölteni az értelmezőbe, akkor válaszul egy típusra vonatkozó hibaüzenetet fogunk kapni, amely tájékoztat arról, hogy nincs minden rendben: GHCi> :load Fail.hs [1 of 1] Compiling Main ( Fail.hs, interpreted ) Fail.hs:4:33: Occurs check: cannot construct the infinite type: t1 ~ t -> t1 -> t1 Relevant bindings include xs :: [t] (bound at Fail.hs:4:14) x :: t (bound at Fail.hs:4:12) z :: t1 (bound at Fail.hs:4:9) f :: t -> t1 -> t1 (bound at Fail.hs:4:7) 19

23 foldr :: (t -> t1 -> t1) -> t1 -> [t] -> t1 (bound at Fail.hs:3:1) In the first argument of foldr, namely z In the second argument of f, namely (foldr z f xs) Failed, modules loaded: none. Ehhez azonban érdemes hozzátenni, a foldr több különböző változata lehet típusosan helyes annak ellenére, hogy nem felel a fentebb megfogalmazott specifikációnknak. Ezért, bár a típusleírást nem minden esetben kötelező megadnunk, jó programozási gyakorlatnak számít, ha a fontosabb függvények definíciójának részeként annak típusát is megadjuk. Ez segít többek között észrevenni, ha a függvény típusa véletlenül idő közben mégis megváltozna. Például az utolsó sorban az x és f változókat felcseréljük: foldr :: (a -> b -> b) -> b -> [a] -> b foldr _ z [] = z foldr f z (x:xs) = x f (foldr f z xs) Ez explicit típusdeklarációnak köszönhetően azonban a fordító képes rámutatni erre a figyelmetlenségre: [1 of 1] Compiling Main ( Fail.hs, interpreted ) Fail.hs:5:20: Couldn t match expected type (a -> b -> b) -> b -> b with actual type a a is a rigid type variable bound by the type signature for foldr :: (a -> b -> b) -> b -> [a] -> b at Fail.hs:3:10 Relevant bindings include xs :: [a] (bound at Fail.hs:5:14) x :: a (bound at Fail.hs:5:12) z :: b (bound at Fail.hs:5:9) f :: a -> b -> b (bound at Fail.hs:5:7) foldr :: (a -> b -> b) -> b -> [a] -> b (bound at Fail.hs:4:1) The function x is applied to two arguments, but its type a has none In the expression: x f (foldr f z xs) In an equation for foldr : foldr f z (x : xs) = x f (foldr f z xs) Failed, modules loaded: none. 20

24 1.7. Részlegesen alkalmazott függvények Ha visszaemlékszünk, volt egy másik magasabbrendű függvényünk is, a map. Ennek a típusát is le lehet kérdezni: GHCi> :type map map :: (a -> b) -> [a] -> [b] A definíció alapján a korábban informálisan bemutatott gondolkodásmód alapján a foldr függvényhez hasonlóan ennek a legáltalánosabb típusa is kikövetkeztethető. Amikor viszont a példában a negate függvénnyel használtuk, a típusban szereplő (a és b) típusváltozókat az Integer típusra szűkítettük: GHCi> map negate [1,-1,2,-2,3,-3] [-1,1,-2,2,-3,3] Azonban érdemes megjegyezni, hogy a map függvénynek nem csak egyparaméteres függvényeket tudunk átadni. Haskellben, mivel a többparaméteres függvények értelmezési tartományait nem Descartes-szorzatokkal ábrázoljuk, lehetőségünk nyílik arra, hogy a függvényeket részlegesen, vagyis az eredeti paraméterszámánál kevesebb paraméterrel alkalmazzuk. Ennek megértéséhez tekintsük a const függvény definícióját: const :: a -> b -> a const x _ = x Ez a függvény két paramétert vár, amelyek közül csak az elsőt adja vissza. GHCi> const GHCi> const True False True Ahogy eddig is láthattuk a (szöveges névvel rendelkező) függvények esetében, az alkalmazásukhoz előre a függvény nevét írjuk, majd az után szóközökkel elválasztva felsoroljuk a paramétereit. Most viszont hozzátesszük, hogy a függvényalkalmazás valójában egy balasszociatív bináris operátor, maga a szóköz, egyik oldalán a függvénnyel, másik oldalán annak paraméterével. Ezt láthatóvá tudjuk tenni úgy, ha az előbbi kifejezésben az összes függvényalkalmazást bezárójelezünk: 21

25 GHCi> ((const True) False) True Mindemellett a const True kifejezés típusát is le tudjuk kérdezni: GHCi> :type const True const True :: b -> Bool Ebből kiderül, hogy az egyik paraméter elhagyásával egyszerűen létrehoztunk egy másik függvényt. Ez egyben meg tudja magyarázni, hogy a nyelv kialakításakor miért így kezdték el ábrázolni a függvényeket. Megjegyezzük, ennek következményeként a -> típusoperátor jobbasszociatív lesz, így a const típusa a következőképpen lesz leírható: const :: a -> (b -> a) Ez a tulajdonság hasznosnak tud bizonyulni a magasabbrendű függvények alkalmazása során is. Vegyük például a map függvényt, ahol az első paraméternek a const függvény is megadható, amennyiben annak első paraméterét rögzítjük a korábbi módon: GHCi> map (const True) [1..5] [True,True,True,True,True] Ekkor a listában szereplő számok egyike sem megjelenni az eredményként keletkező listában, egyedül a True konstans fog egymás után a számuknak, vagyis a lista hosszának megfelelően ismétlődni Típusok Minden, eddig szerepelt függvénynek természetesen ugyanúgy van típusa, például a negate esetében: negate x = 0 - x a típusa a következő: GHCi> :type negate negate :: Num a => a -> a 22

26 Ez szinte teljesen tud illeszkedni ahhoz a naiv sejtésünkhöz, mely szerint ez egy egyparaméteres függvény, amely a paraméterével azonos típusú értéket hoz létre. Egyedüli eltérés ettől a típusban a Num a => előtag megjelenése. Ezt a típusváltozóra vonatkozó megszorításnak vagy röviden csak megszorításnak hívják, és a - operátor alkalmazásából kaptuk: GHCi> :type (-) (-) :: Num a => a -> a -> a Azt már tudhatjuk, hogy a típusváltozók jelenléte polimorf függvényekre utal. Ezért azt mondhatjuk, hogy a - több különböző típusú értékre is felhasználható. A típusváltozók általában tetszőleges Haskellbeli típusra kicserélhetőek. Viszont ha a típus leírásához rájuk vonatkozóan egy megszorítás is megjelenik, akkor azzal a behelyettesíthető típusokat lényegében leszűkítjük egy adott csoport elemeire. A Num is egy ilyen csoport, pontosabban osztály, amely azon típusok osztályát jelenti, amelyek számokat ábrázolnak. Haskellben ilyen típusok például az Integer vagy Double, így a - művelet mind a két esetben alkalmazható, miközben az adott típusra jellemző változatot használjuk a háttérben. Ez úgy is felfogható, mint a függvénynevek túlterhelése, amikor ugyanaz a név több típus esetén is újrahasznosítható. Vagy megfordítva, ugyanaz a függvény a típustól függően többféleképpen képes viselkedni. Ezt eseti, vagy ad hoc polimorfizmusnak szokták nevezni. GHCi> -- (-) :: Double -> Double -> Double GHCi> GHCi> -- (-) :: Integer -> Integer -> Integer GHCi> De a Num osztály nem csak a - operátort tartalmazza, hanem benne megtalálható minden, számokkal kapcsolatos általános művelet. Erről bővebb tájékoztatást az értelmezőn keresztül az :info vagy röviden :i paranccsal kérhetünk: GHCi> :info Num class Num a where (+) :: a -> a -> a (-) :: a -> a -> a (*) :: a -> a -> a negate :: a -> a 23

27 abs :: a -> a signum :: a -> a frominteger :: Integer -> a -- Defined in GHC.Num instance Num Word -- Defined in GHC.Num instance Num Integer -- Defined in GHC.Num instance Num Int -- Defined in GHC.Num instance Num Float -- Defined in GHC.Float instance Num Double -- Defined in GHC.Float A class kulcsszó egy ilyen típusosztályt vezet be, amely után annak neve szerepel, ebben az esetben a Num, majd egy típusváltozó. Ezt a változót tudjuk az osztály leírásában arra használni, hogy megadjuk az összes olyan függvényt, amelynek rendelkeznie kell valamilyen definícióval az összes olyan típus esetében, amelyek ennek az osztálynak az elemei. A típusosztályokat ún. példányok megadásával a forráskód bármelyik részén bővíthetjük. Ehhez mindössze annyit kell tennünk, hogy az instance kulcsszóval bevezetve megadjuk az osztály nevét és a típusváltozó helyére kitöltjük azt a típust, amelyre vonatkozóan az osztályban szereplő függvényeket meg akarjuk adni. Fontos azonban éles különbséget tennünk a típusosztályok és az objektumorientált paradigmában megjelenő osztályok fogalmai között. Habár valóban vonható köztük valamilyen szinten párhuzam, a típusosztályok az objektumorientált terminológia szerint inkább absztrakt interfészeknek tekinthetőek. Meglepő módon azonban nem csak függvények, hanem konstansok (amelyek tulajdonképpen paraméter nélküli függvények) is lehetnek esetlegesen polimorfak. Erre példaként tekintsük az 1 konstanst: GHCi> :type 1 1 :: Num a => a Miért is pontosítanánk az 1 szimbólum típusát annál jobban, mint hogy azt mondjuk róla, az egy szám? Tekinthetnénk egész vagy lebegőpontos számnak egyaránt, a tényleges ábrázolásáról ez az írásmód nem ad információt. Az ábrázolás a használat során fog (lusta módon) egyre pontosabbá válni. Nézzük meg erre példaként a következő kifejezést: GHCi> :type 1 / 3 1 / 3 :: Fractional a => a Itt egy másik típusmegszorítás kerül elő, amely azt állítja, hogy az 1 / 3 nem egyszerűen valamilyen szám, hanem törtszám. A / (osztás) használata miatt kizártuk az egész számokat. A Fractional osztály a Num egy alosztálya, amely további megkötéseket tartalmaz a típusváltozóra: 24

28 GHCi> :info Fractional class Num a => Fractional a where (/) :: a -> a -> a recip :: a -> a fromrational :: Rational -> a -- Defined in GHC.Real instance Fractional Float -- Defined in GHC.Float instance Fractional Double -- Defined in GHC.Float Hozzátesszük, hogy amikor az értelmezőben ki akarjuk egy ilyen kifejezés értékét számítani, az eredmény meghatározásához végül kénytelenek leszünk az osztályból valamelyik konkrét típust kiválasztani: GHCi> 1 / Ez az értelmező erre a célra beépített mechanizmusán keresztül történik, ahol a törtszámok esetében a Double típusra szűkített le. A :: használatával azonban lehetőségünk van a kifejezésekhez típusinformációt fűzni, és ezzel mi magunk is szabályozni tudjuk, hogy az adott polimorf típusból milyen konkrét, ún. monomorf típust hozzuk létre. GHCi> 1 / 3 :: Float Ezt viszont nem szabad összetévesztenünk esetleg más programozási nyelvekből ismert típuskényszerítés fogalmával. A Haskell egy szigorúan típusos nyelv, ezért a típusrendszere nem engedi meg azt, hogy anélkül megváltoztassuk egy kifejezés típusát, hogy ne adnánk meg a régi és új típus közti konverziót végző függvényt (a kifejezés részeként). Ennek az elvnek az elhagyásával a rendszer nem lenne képes a programok helyességére garanciákat nyújtani. GHCi> (1 / 3 :: Float) :: Double <interactive>:2:2: Couldn t match expected type Double with actual type Float In the expression: (1 / 3 :: Float) :: Double In an equation for it : it = (1 / 3 :: Float) :: Double Szerencsére a számok különböző típusai között számos konverziós függvény elérhető. Ebben az esetben realtofrac használható a kívánt hatás elérésére: 25

2019, Funkcionális programozás. 2. el adás. MÁRTON Gyöngyvér

2019, Funkcionális programozás. 2. el adás. MÁRTON Gyöngyvér Funkcionális programozás 2. el adás Sapientia Egyetem, Matematika-Informatika Tanszék Marosvásárhely, Románia mgyongyi@ms.sapientia.ro 2019, tavaszi félév Mir l volt szó? Követelmények, osztályozás Programozási

Részletesebben

FUNKCIONÁLIS PROGRAMOZÁS ELŐADÁS JEGYZET

FUNKCIONÁLIS PROGRAMOZÁS ELŐADÁS JEGYZET FUNKCIONÁLIS PROGRAMOZÁS ELŐADÁS JEGYZET Szerkesztette: Balogh Tamás 2013. május 30. Ha hibát találsz, kérlek jelezd a info@baloghtamas.hu e-mail címen! Ez a Mű a Creative Commons Nevezd meg! - Ne add

Részletesebben

FUNKCIONÁLIS PROGRAMOZÁS GYAKORLAT JEGYZET

FUNKCIONÁLIS PROGRAMOZÁS GYAKORLAT JEGYZET FUNKCIONÁLIS PROGRAMOZÁS GYAKORLAT JEGYZET Szerkesztette: Balogh Tamás 2013. május 17. Ha hibát találsz, kérlek jelezd a info@baloghtamas.hu e-mail címen! Ez a Mű a Creative Commons Nevezd meg! - Ne add

Részletesebben

Alapok. tisztán funkcionális nyelv, minden függvény (a konstansok is) nincsenek hagyományos változók, az első értékadás után nem módosíthatók

Alapok. tisztán funkcionális nyelv, minden függvény (a konstansok is) nincsenek hagyományos változók, az első értékadás után nem módosíthatók Haskell 1. Alapok tisztán funkcionális nyelv, minden függvény (a konstansok is) nincsenek hagyományos változók, az első értékadás után nem módosíthatók elég jól elkerülhetők így a mellékhatások könnyebben

Részletesebben

2016, Funkcionális programozás

2016, Funkcionális programozás Funkcionális programozás 2. előadás Sapientia Egyetem, Műszaki és Humántudományok Tanszék Marosvásárhely, Románia mgyongyi@ms.sapientia.ro 2016, tavaszi félév Miről volt szó? Programozási paradigmák: imperatív,

Részletesebben

Funkcionális és logikai programozás. { Márton Gyöngyvér, 2012} { Sapientia, Erdélyi Magyar Tudományegyetem }

Funkcionális és logikai programozás. { Márton Gyöngyvér, 2012} { Sapientia, Erdélyi Magyar Tudományegyetem } Funkcionális és logikai programozás { Márton Gyöngyvér, 2012} { Sapientia, Erdélyi Magyar Tudományegyetem } http://www.ms.sapientia.ro/~mgyongyi ` 1 Jelenlét: Követelmények, osztályozás Az első 4 előadáson

Részletesebben

BASH script programozás II. Vezérlési szerkezetek

BASH script programozás II. Vezérlési szerkezetek 06 BASH script programozás II. Vezérlési szerkezetek Emlékeztető Jelölésbeli különbség van parancs végrehajtása és a parancs kimenetére való hivatkozás között PARANCS $(PARANCS) Jelölésbeli különbség van

Részletesebben

2018, Funkcionális programozás

2018, Funkcionális programozás Funkcionális programozás 3. előadás Sapientia Egyetem, Matematika-Informatika Tanszék Marosvásárhely, Románia mgyongyi@ms.sapientia.ro 2018, tavaszi félév Miről volt szó? A Haskell programozási nyelv főbb

Részletesebben

Kifejezések. Kozsik Tamás. December 11, 2016

Kifejezések. Kozsik Tamás. December 11, 2016 Kifejezések Kozsik Tamás December 11, 2016 Kifejezések Lexika Szintaktika Szemantika Lexika azonosítók (változó-, metódus-, típus- és csomagnevek) literálok operátorok, pl. + zárójelek: (), [], {},

Részletesebben

1. Alapok. #!/bin/bash

1. Alapok. #!/bin/bash 1. oldal 1.1. A programfájlok szerkezete 1. Alapok A bash programok tulajnképpen egyszerű szöveges fájlok, amelyeket bármely szövegszerkesztő programmal megírhatunk. Alapvetően ugyanazokat a at használhatjuk

Részletesebben

Kifejezések. Kozsik Tamás. December 11, 2016

Kifejezések. Kozsik Tamás. December 11, 2016 Kifejezések Kozsik Tamás December 11, 2016 Kifejezés versus utasítás C/C++: kifejezés plusz pontosvessző: utasítás kiértékeli a kifejezést jellemzően: mellékhatása is van például: értékadás Ada: n = 5;

Részletesebben

FUNKCIONÁLIS PROGRAMOZÁS

FUNKCIONÁLIS PROGRAMOZÁS FUNKCIONÁLIS PROGRAMOZÁS A funkcionális programozás néhány jellemzője Funkcionális programozás 1-2 Funkcionális, más néven applikatív programozás Funkcionális = függvényalapú, függvényközpontú Applikatív

Részletesebben

Amortizációs költségelemzés

Amortizációs költségelemzés Amortizációs költségelemzés Amennyiben műveleteknek egy M 1,...,M m sorozatának a futási idejét akarjuk meghatározni, akkor egy lehetőség, hogy külön-külön minden egyes művelet futási idejét kifejezzük

Részletesebben

2019, Funkcionális programozás. 5. el adás. MÁRTON Gyöngyvér

2019, Funkcionális programozás. 5. el adás. MÁRTON Gyöngyvér Funkcionális programozás 5. el adás Sapientia Egyetem, Matematika-Informatika Tanszék Marosvásárhely, Románia mgyongyi@ms.sapientia.ro 2019, tavaszi félév Mir l volt szó? a Haskell kiértékelési stratégiája

Részletesebben

AWK programozás, minták, vezérlési szerkezetek

AWK programozás, minták, vezérlési szerkezetek 10 AWK programozás, minták, vezérlési szerkezetek AWK adatvezérelt szkriptnyelv text processing, adat kiterjesztés, tagolt adatok automatizált soronkénti feldolgozása a forrásállományt soronként beolvassa

Részletesebben

A függvény kód szekvenciáját kapcsos zárójelek közt definiáljuk, a { } -ek közti részt a Bash héj kód blokknak (code block) nevezi.

A függvény kód szekvenciáját kapcsos zárójelek közt definiáljuk, a { } -ek közti részt a Bash héj kód blokknak (code block) nevezi. Függvények 1.Függvények...1 1.1.A függvény deníció szintaxisa... 1..Függvények érték visszatérítése...3 1.3.Környezettel kapcsolatos kérdések...4 1.4.Lokális változók használata...4 1.5.Rekurzív hívások...5.kód

Részletesebben

Vezérlési szerkezetek

Vezérlési szerkezetek Vezérlési szerkezetek Szelekciós ok: if, else, switch If Segítségével valamely ok végrehajtását valamely feltétel teljesülése esetén végezzük el. Az if segítségével valamely tevékenység () végrehajtását

Részletesebben

Rekurzió. Dr. Iványi Péter

Rekurzió. Dr. Iványi Péter Rekurzió Dr. Iványi Péter 1 Függvényhívás void f3(int a3) { printf( %d,a3); } void f2(int a2) { f3(a2); a2 = (a2+1); } void f1() { int a1 = 1; int b1; b1 = f2(a1); } 2 Függvényhívás void f3(int a3) { printf(

Részletesebben

C++ referencia. Izsó Tamás február 17. A C++ nyelvben nagyon sok félreértés van a referenciával kapcsolatban. A Legyakoribb hibák:

C++ referencia. Izsó Tamás február 17. A C++ nyelvben nagyon sok félreértés van a referenciával kapcsolatban. A Legyakoribb hibák: C++ referencia Izsó Tamás 2017. február 17. 1. Bevezetés A C++ nyelvben nagyon sok félreértés van a referenciával kapcsolatban. A Legyakoribb hibák: Sokan összetévesztik a pointerrel. Keveset alkalmazzák

Részletesebben

First Prev Next Last Go Back Full Screen Close Quit. Matematika I

First Prev Next Last Go Back Full Screen Close Quit. Matematika I Matematika I (Analízis) Készítette: Horváth Gábor Kötelező irodalom: Ács László, Gáspár Csaba: Analízis 1 Oktatási segédanyagok és a tantárgyi követelményrendszer megtalálható a http://rs1.szif.hu/ horvathg/horvathg.html

Részletesebben

2019, Funkcionális programozás. 4. el adás. MÁRTON Gyöngyvér

2019, Funkcionális programozás. 4. el adás. MÁRTON Gyöngyvér Funkcionális programozás 4. el adás Sapientia Egyetem, Matematika-Informatika Tanszék Marosvásárhely, Románia mgyongyi@ms.sapientia.ro 2019, tavaszi félév Mir l volt szó? GHC parancsok fenntartott szavak

Részletesebben

Már megismert fogalmak áttekintése

Már megismert fogalmak áttekintése Interfészek szenasi.sandor@nik.bmf.hu PPT 2007/2008 tavasz http://nik.bmf.hu/ppt 1 Témakörök Polimorfizmus áttekintése Interfészek Interfészek kiterjesztése Eseménykezelési módszerek 2 Már megismert fogalmak

Részletesebben

Occam 1. Készítette: Szabó Éva

Occam 1. Készítette: Szabó Éva Occam 1. Készítette: Szabó Éva Párhuzamos programozás Egyes folyamatok (processzek) párhuzamosan futnak. Több processzor -> tényleges párhuzamosság Egy processzor -> Időosztásos szimuláció Folyamatok közötti

Részletesebben

Programozási nyelvek (ADA)

Programozási nyelvek (ADA) Programozási nyelvek (ADA) Kozsik Tamás előadása alapján Készítette: Nagy Krisztián 1. előadás Hasznos weboldal http://kto.web.elte.hu Program felépítése Programegységek (program unit) eljárások (procedure)

Részletesebben

2018, Funkcionális programozás

2018, Funkcionális programozás Funkcionális programozás 1. előadás Sapientia Egyetem, Matematika-Informatika Tanszék Marosvásárhely, Románia mgyongyi@ms.sapientia.ro 2018, tavaszi félév Követelmények, osztályozás Előadás, jelenlét:

Részletesebben

Webprogramozás szakkör

Webprogramozás szakkör Webprogramozás szakkör Előadás 5 (2012.04.09) Programozás alapok Eddig amit láttunk: Programozás lépései o Feladat leírása (specifikáció) o Algoritmizálás, tervezés (folyamatábra, pszeudokód) o Programozás

Részletesebben

Programozás alapjai gyakorlat. 2. gyakorlat C alapok

Programozás alapjai gyakorlat. 2. gyakorlat C alapok Programozás alapjai gyakorlat 2. gyakorlat C alapok 2016-2017 Bordé Sándor 2 Forráskód, fordító, futtatható állomány Először megírjuk a programunk kódját (forráskód) Egyszerű szövegszerkesztőben vagy fejlesztőkörnyezettel

Részletesebben

Java II. I A Java programozási nyelv alapelemei

Java II. I A Java programozási nyelv alapelemei Java II. I A Java programozási nyelv alapelemei Miskolci Egyetem Általános Informatikai Tanszék Utolsó módosítás: 2008. 02. 19. Java II.: Alapelemek JAVA2 / 1 A Java formalizmusa A C, illetve az annak

Részletesebben

Programozás C és C++ -ban

Programozás C és C++ -ban Programozás C és C++ -ban 2. További különbségek a C és C++ között 2.1 Igaz és hamis A C++ programozási nyelv a C-hez hasonlóan definiál néhány alap adattípust: char int float double Ugyanakkor egy új

Részletesebben

1. Egyszerű (primitív) típusok. 2. Referencia típusok

1. Egyszerű (primitív) típusok. 2. Referencia típusok II. A Java nyelv eszközei 1. Milyen eszközöket nyújt a Java a programozóknak Korábban már említettük, hogy a Java a C nyelvből alakult ki, ezért a C, C++ nyelvben járatos programozóknak nem fog nehézséget

Részletesebben

SZÁMÍTÁSOK A TÁBLÁZATBAN

SZÁMÍTÁSOK A TÁBLÁZATBAN SZÁMÍTÁSOK A TÁBLÁZATBAN Az Excelben az egyszerű adatok bevitelén kívül számításokat is végezhetünk. Ezeket a cellákba beírt képletek segítségével oldjuk meg. A képlet: olyan egyenlet, amely a munkalapon

Részletesebben

6. Függvények. 1. Az alábbi függvények közül melyik szigorúan monoton növekvő a 0;1 intervallumban?

6. Függvények. 1. Az alábbi függvények közül melyik szigorúan monoton növekvő a 0;1 intervallumban? 6. Függvények I. Nulladik ZH-ban láttuk: 1. Az alábbi függvények közül melyik szigorúan monoton növekvő a 0;1 intervallumban? f x g x cos x h x x ( ) sin x (A) Az f és a h. (B) Mindhárom. (C) Csak az f.

Részletesebben

2010. október 12. Dr. Vincze Szilvia

2010. október 12. Dr. Vincze Szilvia 2010. október 12. Dr. Vincze Szilvia Tartalomjegyzék 1.) Sorozat definíciója 2.) Sorozat megadása 3.) Sorozatok szemléltetése 4.) Műveletek sorozatokkal 5.) A sorozatok tulajdonságai 6.) A sorozatok határértékének

Részletesebben

KOVÁCS BÉLA, MATEMATIKA I.

KOVÁCS BÉLA, MATEMATIKA I. KOVÁCS BÉLA, MATEmATIkA I. 4 IV. FÜGGVÉNYEk 1. LEkÉPEZÉSEk, függvények Definíció Legyen és két halmaz. Egy függvény -ből -ba egy olyan szabály, amely minden elemhez pontosan egy elemet rendel hozzá. Az

Részletesebben

Komputeralgebra rendszerek

Komputeralgebra rendszerek Komputeralgebra rendszerek III. Változók Czirbusz Sándor czirbusz@gmail.com Komputeralgebra Tanszék ELTE Informatika Kar 2009-2010 ősz Index I 1 Szimbolikus konstansok kezelés A konstansok Nevek levédése

Részletesebben

AWK programozás Bevezetés

AWK programozás Bevezetés 09 AWK programozás Bevezetés AWK adatvezérelt szkriptnyelv text processing, adat kiterjesztés, tagolt adatok automatizált soronkénti feldolgozása a forrásállományt soronként beolvassa és feldolgozhatóvá

Részletesebben

Brósch Zoltán (Debreceni Egyetem Kossuth Lajos Gyakorló Gimnáziuma) Számelmélet I.

Brósch Zoltán (Debreceni Egyetem Kossuth Lajos Gyakorló Gimnáziuma) Számelmélet I. Számelmélet I. DEFINÍCIÓ: (Osztó, többszörös) Ha egy a szám felírható egy b szám és egy másik egész szám szorzataként, akkor a b számot az a osztójának, az a számot a b többszörösének nevezzük. Megjegyzés:

Részletesebben

Komputeralgebra rendszerek

Komputeralgebra rendszerek Komputeralgebra rendszerek III. Változók Czirbusz Sándor czirbusz@gmail.com Komputeralgebra Tanszék ELTE Informatika Kar 2009-2010 ősz Index I 1 Szimbolikus konstansok kezelés A konstansok Nevek levédése

Részletesebben

Programozás BMEKOKAA146. Dr. Bécsi Tamás 2. előadás

Programozás BMEKOKAA146. Dr. Bécsi Tamás 2. előadás Programozás BMEKOKAA146 Dr. Bécsi Tamás 2. előadás Szintaktikai alapok Alapvető típusok, ismétlés C# típus.net típus Méret (byte) Leírás byte System.Byte 1Előjel nélküli 8 bites egész szám (0..255) char

Részletesebben

Java programozási nyelv

Java programozási nyelv Java programozási nyelv 2. rész Vezérlő szerkezetek Nyugat-Magyarországi Egyetem Faipari Mérnöki Kar Informatikai Intézet Soós Sándor 2005. szeptember A Java programozási nyelv Soós Sándor 1/23 Tartalomjegyzék

Részletesebben

2018, Funkcionális programozás

2018, Funkcionális programozás Funkcionális programozás 6. előadás Sapientia Egyetem, Matematika-Informatika Tanszék Marosvásárhely, Románia mgyongyi@ms.sapientia.ro 2018, tavaszi félév Miről volt szó? Haskell modulok, kompilálás a

Részletesebben

KOVÁCS BÉLA, MATEMATIKA I.

KOVÁCS BÉLA, MATEMATIKA I. KOVÁCS BÉLA MATEmATIkA I 6 VI KOmPLEX SZÁmOk 1 A komplex SZÁmOk HALmAZA A komplex számok olyan halmazt alkotnak amelyekben elvégezhető az összeadás és a szorzás azaz két komplex szám összege és szorzata

Részletesebben

ALGORITMIKUS SZERKEZETEK ELÁGAZÁSOK, CIKLUSOK, FÜGGVÉNYEK

ALGORITMIKUS SZERKEZETEK ELÁGAZÁSOK, CIKLUSOK, FÜGGVÉNYEK ALGORITMIKUS SZERKEZETEK ELÁGAZÁSOK, CIKLUSOK, FÜGGVÉNYEK 1. ELÁGAZÁSOK ÉS CIKLUSOK SZERVEZÉSE Az adatszerkezetek mellett a programok másik alapvető fontosságú építőkövei az ún. algoritmikus szerkezetek.

Részletesebben

5. SOR. Üres: S Sorba: S E S Sorból: S S E Első: S E

5. SOR. Üres: S Sorba: S E S Sorból: S S E Első: S E 5. SOR A sor adatszerkezet is ismerős a mindennapokból, például a várakozási sornak számos előfordulásával van dolgunk, akár emberekről akár tárgyakról (pl. munkadarabokról) legyen szó. A sor adattípus

Részletesebben

Oktatási segédlet 2014

Oktatási segédlet 2014 Oktatási segédlet 2014 A kutatás a TÁMOP 4.2.4.A/2-11-1-2012- 0001 azonosító számú Nemzeti Kiválóság Program Hazai hallgatói, illetve kutatói személyi támogatást biztosító rendszer kidolgozása és működtetése

Részletesebben

KOVÁCS BÉLA, MATEMATIKA I.

KOVÁCS BÉLA, MATEMATIKA I. KOVÁCS BÉLA, MATEmATIkA I. 1 I. HALmAZOk 1. JELÖLÉSEk A halmaz fogalmát tulajdonságait gyakran használjuk a matematikában. A halmazt nem definiáljuk, ezt alapfogalomnak tekintjük. Ez nem szokatlan, hiszen

Részletesebben

Funkcionális Nyelvek 2 (MSc)

Funkcionális Nyelvek 2 (MSc) Funkcionális Nyelvek 2 (MSc) Páli Gábor János pgj@elte.hu Eötvös Loránd Tudományegyetem Informatikai Kar Programozási Nyelvek és Fordítóprogramok Tanszék Tematika A (tervezett) tematika rövid összefoglalása

Részletesebben

Szkriptnyelvek. 1. UNIX shell

Szkriptnyelvek. 1. UNIX shell Szkriptnyelvek 1. UNIX shell Szkriptek futtatása Parancsértelmez ő shell script neve paraméterek shell script neve paraméterek Ebben az esetben a szkript tartalmazza a parancsértelmezőt: #!/bin/bash Szkriptek

Részletesebben

Formális nyelvek és automaták

Formális nyelvek és automaták Formális nyelvek és automaták Nagy Sára gyakorlatai alapján Készítette: Nagy Krisztián 2. gyakorlat Ismétlés: Megjegyzés: Az ismétlés egy része nem szerepel a dokumentumban, mivel lényegében a teljes 1.

Részletesebben

f(x) vagy f(x) a (x x 0 )-t használjuk. lim melyekre Mivel itt ɛ > 0 tetszőlegesen kicsi, így a a = 0, a = a, ami ellentmondás, bizonyítva

f(x) vagy f(x) a (x x 0 )-t használjuk. lim melyekre Mivel itt ɛ > 0 tetszőlegesen kicsi, így a a = 0, a = a, ami ellentmondás, bizonyítva 6. FÜGGVÉNYEK HATÁRÉRTÉKE ÉS FOLYTONOSSÁGA 6.1 Függvény határértéke Egy D R halmaz torlódási pontjainak halmazát D -vel fogjuk jelölni. Definíció. Legyen f : D R R és legyen x 0 D (a D halmaz torlódási

Részletesebben

Alkalmazott modul: Programozás 4. előadás. Procedurális programozás: iteratív és rekurzív alprogramok. Alprogramok. Alprogramok.

Alkalmazott modul: Programozás 4. előadás. Procedurális programozás: iteratív és rekurzív alprogramok. Alprogramok. Alprogramok. Eötvös Loránd Tudományegyetem Informatikai Kar Alkalmazott modul: Programozás 4. előadás Procedurális programozás: iteratív és rekurzív alprogramok Giachetta Roberto groberto@inf.elte.hu http://people.inf.elte.hu/groberto

Részletesebben

Tömbök kezelése. Példa: Vonalkód ellenőrzőjegyének kiszámítása

Tömbök kezelése. Példa: Vonalkód ellenőrzőjegyének kiszámítása Tömbök kezelése Példa: Vonalkód ellenőrzőjegyének kiszámítása A számokkal jellemzett adatok, pl. személyi szám, adószám, taj-szám, vonalkód, bankszámlaszám esetében az elírásból származó hibát ún. ellenőrző

Részletesebben

HORVÁTH ZSÓFIA 1. Beadandó feladat (HOZSAAI.ELTE) ápr 7. 8-as csoport

HORVÁTH ZSÓFIA 1. Beadandó feladat (HOZSAAI.ELTE) ápr 7. 8-as csoport 10-es Keressünk egy egész számokat tartalmazó négyzetes mátrixban olyan oszlopot, ahol a főátló alatti elemek mind nullák! Megolda si terv: Specifika cio : A = (mat: Z n m,ind: N, l: L) Ef =(mat = mat`)

Részletesebben

Interfészek. PPT 2007/2008 tavasz.

Interfészek. PPT 2007/2008 tavasz. Interfészek szenasi.sandor@nik.bmf.hu PPT 2007/2008 tavasz http://nik.bmf.hu/ppt 1 Témakörök Polimorfizmus áttekintése Interfészek Interfészek kiterjesztése 2 Már megismert fogalmak áttekintése Objektumorientált

Részletesebben

Programozás alapjai gyakorlat. 4. gyakorlat Konstansok, tömbök, stringek

Programozás alapjai gyakorlat. 4. gyakorlat Konstansok, tömbök, stringek Programozás alapjai gyakorlat 4. gyakorlat Konstansok, tömbök, stringek Házi ellenőrzés (f0069) Valósítsd meg a linuxos seq parancs egy egyszerűbb változatát, ami beolvas két egész számot, majd a kettő

Részletesebben

Programozás alapjai (ANSI C)

Programozás alapjai (ANSI C) Programozás alapjai (ANSI C) 1. Előadás vázlat A számítógép és programozása Dr. Baksáné dr. Varga Erika adjunktus Miskolci Egyetem, Informatikai Intézet Általános Informatikai Intézeti Tanszék www.iit.uni-miskolc.hu

Részletesebben

OOP. Alapelvek Elek Tibor

OOP. Alapelvek Elek Tibor OOP Alapelvek Elek Tibor OOP szemlélet Az OOP szemlélete szerint: a valóságot objektumok halmazaként tekintjük. Ezen objektumok egymással kapcsolatban vannak és együttműködnek. Program készítés: Absztrakciós

Részletesebben

Készítette: Nagy Tibor István

Készítette: Nagy Tibor István Készítette: Nagy Tibor István Operátorok Műveletek Egy (vagy több) műveleti jellel írhatók le A műveletet operandusaikkal végzik Operátorok fajtái operandusok száma szerint: egyoperandusú operátorok (pl.:

Részletesebben

GENERIKUS PROGRAMOZÁS Osztálysablonok, Általános felépítésű függvények, Függvénynevek túlterhelése és. Függvénysablonok

GENERIKUS PROGRAMOZÁS Osztálysablonok, Általános felépítésű függvények, Függvénynevek túlterhelése és. Függvénysablonok GENERIKUS PROGRAMOZÁS Osztálysablonok, Általános felépítésű függvények, Függvénynevek túlterhelése és Függvénysablonok Gyakorlatorientált szoftverfejlesztés C++ nyelven Visual Studio Community fejlesztőkörnyezetben

Részletesebben

2018, Diszkrét matematika

2018, Diszkrét matematika Diszkrét matematika 3. előadás mgyongyi@ms.sapientia.ro Sapientia Egyetem, Matematika-Informatika Tanszék Marosvásárhely, Románia 2018, őszi félév Miről volt szó az elmúlt előadáson? számtartományok: természetes

Részletesebben

S2-01 Funkcionális nyelvek alapfogalmai

S2-01 Funkcionális nyelvek alapfogalmai S2-01 Funkcionális nyelvek alapfogalmai Tartalom 1. Funkcionális nyelvek alapfogalmai Modell Kiértékelés Curry-zés Magasabbrendű függvények Listák Tisztaság 2. Típusok Algebrai adattípusok Típusosztályok

Részletesebben

Adatszerkezetek Tömb, sor, verem. Dr. Iványi Péter

Adatszerkezetek Tömb, sor, verem. Dr. Iványi Péter Adatszerkezetek Tömb, sor, verem Dr. Iványi Péter 1 Adat Adat minden, amit a számítógépünkben tárolunk és a külvilágból jön Az adatnak két fontos tulajdonsága van: Értéke Típusa 2 Adat típusa Az adatot

Részletesebben

Általános algoritmustervezési módszerek

Általános algoritmustervezési módszerek Általános algoritmustervezési módszerek Ebben a részben arra mutatunk példát, hogy miként használhatóak olyan általános algoritmustervezési módszerek mint a dinamikus programozás és a korlátozás és szétválasztás

Részletesebben

AWK programozás, minták, vezérlési szerkezetek

AWK programozás, minták, vezérlési szerkezetek 10 AWK programozás, minták, vezérlési szerkezetek AWK futtatási módok AWK parancs, közvetlen programkódmegadás: awk 'PROGRAMKÓD' FILE példa: ls -l awk '{print $1, $5}' a programkód helyére minden indentálás

Részletesebben

PHP. Telepítése: Indítás/újraindítás/leállítás: Beállítások: A PHP nyelv

PHP. Telepítése: Indítás/újraindítás/leállítás: Beállítások: A PHP nyelv PHP A PHP rövidítés jelentése hivatalosan: PHP Hypertext Preprocessor. Ez egy kiszolgáló-oldali parancsnyelv, amit jellemzően HTML oldalakon használnak. A különbség a két nyelv között az, hogy a kiszolgáló

Részletesebben

Segédanyagok. Formális nyelvek a gyakorlatban. Szintaktikai helyesség. Fordítóprogramok. Formális nyelvek, 1. gyakorlat

Segédanyagok. Formális nyelvek a gyakorlatban. Szintaktikai helyesség. Fordítóprogramok. Formális nyelvek, 1. gyakorlat Formális nyelvek a gyakorlatban Formális nyelvek, 1 gyakorlat Segédanyagok Célja: A programozási nyelvek szintaxisának leírására használatos eszközök, módszerek bemutatása Fogalmak: BNF, szabály, levezethető,

Részletesebben

Kiterjesztések sek szemantikája

Kiterjesztések sek szemantikája Kiterjesztések sek szemantikája Példa D Integer = {..., -1,0,1,... }; D Boolean = { true, false } D T1... T n T = D T 1... D Tn D T Az összes függvf ggvény halmaza, amelyek a D T1,..., D Tn halmazokból

Részletesebben

Változók. Mennyiség, érték (v. objektum) szimbolikus jelölése, jelentése Tulajdonságai (attribútumai):

Változók. Mennyiség, érték (v. objektum) szimbolikus jelölése, jelentése Tulajdonságai (attribútumai): Python Változók Mennyiség, érték (v. objektum) szimbolikus jelölése, jelentése Tulajdonságai (attribútumai): Név Érték Típus Memóriacím A változó értéke (esetleg más attribútuma is) a program futása alatt

Részletesebben

Mindent olyan egyszerűvé kell tenni, amennyire csak lehet, de nem egyszerűbbé. (Albert Einstein) Halmazok 1

Mindent olyan egyszerűvé kell tenni, amennyire csak lehet, de nem egyszerűbbé. (Albert Einstein) Halmazok 1 Halmazok 1 Mindent olyan egyszerűvé kell tenni, amennyire csak lehet, de nem egyszerűbbé. (Albert Einstein) Halmazok 2 A fejezet legfontosabb elemei Halmaz megadási módjai Halmazok közti műveletek (metszet,

Részletesebben

Halmazelmélet. 1. előadás. Farkas István. DE ATC Gazdaságelemzési és Statisztikai Tanszék. Halmazelmélet p. 1/1

Halmazelmélet. 1. előadás. Farkas István. DE ATC Gazdaságelemzési és Statisztikai Tanszék. Halmazelmélet p. 1/1 Halmazelmélet 1. előadás Farkas István DE ATC Gazdaságelemzési és Statisztikai Tanszék Halmazelmélet p. 1/1 A halmaz fogalma, jelölések A halmaz fogalmát a matematikában nem definiáljuk, tulajdonságaival

Részletesebben

sallang avagy Fordítótervezés dióhéjban Sallai Gyula

sallang avagy Fordítótervezés dióhéjban Sallai Gyula sallang avagy Fordítótervezés dióhéjban Sallai Gyula Az előadás egy kis példaprogramon keresztül mutatja be fordítók belső lelki világát De mit is jelent, az hogy fordítóprogram? Mit csinál egy fordító?

Részletesebben

Operációs rendszerek. 9. gyakorlat. Reguláris kifejezések - alapok, BASH UNIVERSITAS SCIENTIARUM SZEGEDIENSIS UNIVERSITY OF SZEGED

Operációs rendszerek. 9. gyakorlat. Reguláris kifejezések - alapok, BASH UNIVERSITAS SCIENTIARUM SZEGEDIENSIS UNIVERSITY OF SZEGED UNIVERSITAS SCIENTIARUM SZEGEDIENSIS UNIVERSITY OF SZEGED Reguláris kifejezések - alapok, BASH Operációs rendszerek 9. gyakorlat Szegedi Tudományegyetem Természettudományi és Informatikai Kar Csuvik Viktor

Részletesebben

Programozás II. 2. gyakorlat Áttérés C-ről C++-ra

Programozás II. 2. gyakorlat Áttérés C-ről C++-ra Programozás II. 2. gyakorlat Áttérés C-ről C++-ra Tartalom Új kommentelési lehetőség Változók deklarációjának helye Alapértelmezett függvényparaméterek Névterek I/O műveletek egyszerűsödése Logikai adattípus,

Részletesebben

Python tanfolyam Python bevezető I. rész

Python tanfolyam Python bevezető I. rész Python tanfolyam Python bevezető I. rész Mai tematika Amiről szó lesz (most): Interpretált vs. fordított nyelvek, GC Szintakszis Alaptípusok Control flow: szekvencia, szelekció, iteráció... Függvények

Részletesebben

A szemantikus elemzés elmélete. Szemantikus elemzés (attribútum fordítási grammatikák) A szemantikus elemzés elmélete. A szemantikus elemzés elmélete

A szemantikus elemzés elmélete. Szemantikus elemzés (attribútum fordítási grammatikák) A szemantikus elemzés elmélete. A szemantikus elemzés elmélete A szemantikus elemzés elmélete Szemantikus elemzés (attribútum fordítási grammatikák) a nyelvtan szabályait kiegészítjük a szemantikus elemzés tevékenységeivel fordítási grammatikák Fordítóprogramok előadás

Részletesebben

Amit a törtekről tudni kell Minimum követelményszint

Amit a törtekről tudni kell Minimum követelményszint Amit a törtekről tudni kell Minimum követelményszint Fontos megjegyzés: A szabályoknak nem a pontos matematikai meghatározását adtuk. Helyettük a gyakorlatban használható, egyszerű megfogalmazásokat írtunk.

Részletesebben

Információk. Ismétlés II. Ismétlés. Ismétlés III. A PROGRAMOZÁS ALAPJAI 2. Készítette: Vénné Meskó Katalin. Algoritmus. Algoritmus ábrázolása

Információk. Ismétlés II. Ismétlés. Ismétlés III. A PROGRAMOZÁS ALAPJAI 2. Készítette: Vénné Meskó Katalin. Algoritmus. Algoritmus ábrázolása 1 Információk 2 A PROGRAMOZÁS ALAPJAI 2. Készítette: Vénné Meskó Katalin Elérhetőség mesko.katalin@tfk.kefo.hu Fogadóóra: szerda 9:50-10:35 Számonkérés időpontok Április 25. 9 00 Május 17. 9 00 Június

Részletesebben

9. előadás. Programozás-elmélet. Programozási tételek Elemi prog. Sorozatszámítás Eldöntés Kiválasztás Lin. keresés Megszámolás Maximum.

9. előadás. Programozás-elmélet. Programozási tételek Elemi prog. Sorozatszámítás Eldöntés Kiválasztás Lin. keresés Megszámolás Maximum. Programozási tételek Programozási feladatok megoldásakor a top-down (strukturált) programtervezés esetén három vezérlési szerkezetet használunk: - szekvencia - elágazás - ciklus Eddig megismertük az alábbi

Részletesebben

Mindent olyan egyszerűvé kell tenni, amennyire csak lehet, de nem egyszerűbbé.

Mindent olyan egyszerűvé kell tenni, amennyire csak lehet, de nem egyszerűbbé. HA 1 Mindent olyan egyszerűvé kell tenni, amennyire csak lehet, de nem egyszerűbbé. (Albert Einstein) HA 2 Halmazok HA 3 Megjegyzések A halmaz, az elem és az eleme fogalmakat nem definiáljuk, hanem alapfogalmaknak

Részletesebben

A fordítóprogramok szerkezete. Kódoptimalizálás. A kódoptimalizálás célja. A szintézis menete valójában. Kódoptimalizálási lépések osztályozása

A fordítóprogramok szerkezete. Kódoptimalizálás. A kódoptimalizálás célja. A szintézis menete valójában. Kódoptimalizálási lépések osztályozása A fordítóprogramok szerkezete Forrásprogram Forrás-kezelő (source handler) Kódoptimalizálás Fordítóprogramok előadás (A,C,T szakirány) Lexikális elemző (scanner) Szintaktikus elemző (parser) Szemantikus

Részletesebben

van neve lehetnek bemeneti paraméterei (argumentumai) lehet visszatérési értéke a függvényt úgy használjuk, hogy meghívjuk

van neve lehetnek bemeneti paraméterei (argumentumai) lehet visszatérési értéke a függvényt úgy használjuk, hogy meghívjuk függvények ismétlése lista fogalma, használata Game of Life program (listák használatának gyakorlása) listák másolása (alap szintű, teljes körű) Reversi 2 Emlékeztető a függvények lényegében mini-programok,

Részletesebben

I. Egyenlet fogalma, algebrai megoldása

I. Egyenlet fogalma, algebrai megoldása 11 modul: EGYENLETEK, EGYENLŐTLENSÉGEK MEGOLDÁSA 6 I Egyenlet fogalma, algebrai megoldása Módszertani megjegyzés: Az egyenletek alaphalmazát, értelmezési tartományát később vezetjük be, a törtes egyenletekkel

Részletesebben

Leképezések. Leképezések tulajdonságai. Számosságok.

Leképezések. Leképezések tulajdonságai. Számosságok. Leképezések Leképezések tulajdonságai. Számosságok. 1. Leképezések tulajdonságai A továbbiakban legyen A és B két tetszőleges halmaz. Idézzünk fel néhány definíciót. 1. Definíció (Emlékeztető). Relációknak

Részletesebben

A szemantikus elemzés helye. A szemantikus elemzés feladatai. A szemantikus elemzés feladatai. Deklarációk és láthatósági szabályok

A szemantikus elemzés helye. A szemantikus elemzés feladatai. A szemantikus elemzés feladatai. Deklarációk és láthatósági szabályok A szemantikus elemzés helye Forrásprogram Forrás-kezelő (source handler) Lexikális elemző (scanner) A szemantikus elemzés feladatai Fordítóprogramok előadás (A, C, T szakirány) Szintaktikus elemző (parser)

Részletesebben

Bevezetés a programozásba

Bevezetés a programozásba Bevezetés a programozásba 1. Előadás Bevezetés, kifejezések http://digitus.itk.ppke.hu/~flugi/ Egyre precízebb A programozás természete Hozzál krumplit! Hozzál egy kiló krumplit! Hozzál egy kiló krumplit

Részletesebben

Szoftvertervezés és -fejlesztés I.

Szoftvertervezés és -fejlesztés I. Szoftvertervezés és -fejlesztés I. Operátorok Vezérlési szerkezetek Gyakorlás 1 Hallgatói Tájékoztató A jelen bemutatóban található adatok, tudnivalók és információk a számonkérendő anyag vázlatát képezik.

Részletesebben

Excel 2010 függvények

Excel 2010 függvények Molnár Mátyás Excel 2010 függvények Csak a lényeg érthetően! Tartalomjegyzék FÜGGVÉNYHASZNÁLAT ALAPJAI 1 FÜGGVÉNYEK BEVITELE 1 HIBAÉRTÉKEK KEZELÉSE 4 A VARÁZSLATOS AUTOSZUM GOMB 6 SZÁMÍTÁSOK A REJTETT

Részletesebben

NAGYPONTOSSÁGÚ RACIONÁLIS-ARITMETIKA EXCEL VISUAL BASIC KÖRNYEZETBEN TARTALOM

NAGYPONTOSSÁGÚ RACIONÁLIS-ARITMETIKA EXCEL VISUAL BASIC KÖRNYEZETBEN TARTALOM NAGYPONTOSSÁGÚ RACIONÁLIS-ARITMETIKA EXCEL VISUAL BASIC KÖRNYEZETBEN TARTALOM 0. A feladat... 2 1. A racionális számok ábrázolásai... 2 2. A műveletek... 3 A műveletek szignatúrája... 3 A műveletek algoritmusa...

Részletesebben

az Excel for Windows programban

az Excel for Windows programban az Excel for Windows táblázatkezelőblázatkezel programban Mit nevezünk nk képletnek? A táblt blázatkezelő programok nagy előnye, hogy meggyorsítj tják és könnyebbé teszik a felhasználó számára a számítási

Részletesebben

Komputeralgebra Rendszerek

Komputeralgebra Rendszerek Komputeralgebra Rendszerek Konstansok, változók, típusok Czirbusz Sándor ELTE IK, Komputeralgebra Tanszék 2015. február 24. TARTALOMJEGYZÉK 1 of 110 TARTALOMJEGYZÉK I 1 TARTALOMJEGYZÉK 2 Nevek kezelése

Részletesebben

Bevezetés a programozásba II. 5. Előadás: Másoló konstruktor, túlterhelés, operátorok

Bevezetés a programozásba II. 5. Előadás: Másoló konstruktor, túlterhelés, operátorok Bevezetés a programozásba II 5. Előadás: Másoló konstruktor, túlterhelés, operátorok Emlékeztető struct Vektor { int meret, *mut; Vektor(int meret); int szamlal(int mit); }; int Vektor::szamlal(int mit)

Részletesebben

Programozási segédlet

Programozási segédlet Programozási segédlet Programozási tételek Az alábbiakban leírtam néhány alap algoritmust, amit ismernie kell annak, aki programozásra adja a fejét. A lista korántsem teljes, ám ennyi elég kell legyen

Részletesebben

A PiFast program használata. Nagy Lajos

A PiFast program használata. Nagy Lajos A PiFast program használata Nagy Lajos Tartalomjegyzék 1. Bevezetés 3 2. Bináris kimenet létrehozása. 3 2.1. Beépített konstans esete.............................. 3 2.2. Felhasználói konstans esete............................

Részletesebben

Lekérdezések az SQL SELECT utasítással

Lekérdezések az SQL SELECT utasítással Lekérdezések az SQL SELECT utasítással Az SQL SELECT utasítás lehetőségei Vetítés Kiválasztás 1. tábla 1. tábla Összekapcsolás 1. tábla 2. tábla Elemi SELECT utasítások SELECT * {[DISTINCT] column expression

Részletesebben

BASH SCRIPT SHELL JEGYZETEK

BASH SCRIPT SHELL JEGYZETEK BASH SCRIPT SHELL JEGYZETEK 1 TARTALOM Paraméterek... 4 Változók... 4 Környezeti változók... 4 Szűrők... 4 grep... 4 sed... 5 cut... 5 head, tail... 5 Reguláris kifejezések... 6 *... 6 +... 6?... 6 {m,n}...

Részletesebben

Programozás alapjai. 7. előadás

Programozás alapjai. 7. előadás 7. előadás Wagner György Általános Informatikai Tanszék Jótanács (1) Tipikus hiba a feladat elkészítésekor: Jótanács (2) Szintén tipikus hiba: a file-ból való törléskor, illetve a file-nak új elemmel való

Részletesebben

Logika es sz am ıt aselm elet I. r esz Logika 1/36

Logika es sz am ıt aselm elet I. r esz Logika 1/36 1/36 Logika és számításelmélet I. rész Logika 2/36 Elérhetőségek Tejfel Máté Déli épület, 2.606 matej@inf.elte.hu http://matej.web.elte.hu Tankönyv 3/36 Tartalom 4/36 Bevezető fogalmak Ítéletlogika Ítéletlogika

Részletesebben

C programozási nyelv

C programozási nyelv C programozási nyelv Előfeldolgozó utasítások Dr Schuster György 2011 május 3 Dr Schuster György () C programozási nyelv Előfeldolgozó utasítások 2011 május 3 1 / 15 A fordítás menete Dr Schuster György

Részletesebben

Aritmetikai kifejezések lengyelformára hozása

Aritmetikai kifejezések lengyelformára hozása Aritmetikai kifejezések lengyelformára hozása Készítették: Santák Csaba és Kovács Péter, 2005 ELTE IK programtervező matematikus szak Aritmetikai kifejezések kiértékelése - Gyakran felmerülő programozási

Részletesebben

Algoritmusok és adatszerkezetek 2.

Algoritmusok és adatszerkezetek 2. Algoritmusok és adatszerkezetek 2. Varga Balázs gyakorlata alapján Készítette: Nagy Krisztián 1. gyakorlat Nyílt címzéses hash-elés A nyílt címzésű hash táblákban a láncolással ellentétben egy indexen

Részletesebben