ZuriHac: funkcionális programozás gyakorlása

Idén júniusban a svájci kisvárosban, Rapperswilben, az ún ZuriHac. Ezúttal több mint ötszáz Haskell-szeretőt hozott össze, a kezdőktől a nyelvalapító atyákig. Bár a szervezők hackathonnak hívják ezt a rendezvényt, ez nem konferencia vagy klasszikus értelemben vett hackathon. Formátuma eltér a hagyományos programozókétól. A ZuriHacról szerencsére értesültünk, részt vettünk benne, most pedig kötelességünknek tartjuk, hogy beszámoljunk a nem mindennapi leletről!

ZuriHac: funkcionális programozás gyakorlása

Rólunk

Ezt a cikket a Szentpétervári Nemzeti Kutatóegyetem Közgazdasági Főiskola „Alkalmazott Matematika és Informatika” programjának két 3. éves hallgatója készítette: Vaszilij Alferov és Elizaveta Vasilenko. A funkcionális programozás iránti szenvedély mindkettőnk számára D. N. Moskvin előadássorozatával kezdődött az egyetem 2. évfolyamán. Vaszilij jelenleg a Google Summer of Code programban vesz részt, melynek keretében algebrai gráfokat valósít meg Haskellben a projektcsapat irányításával. Alga. Elizaveta az elsajátított funkcionális programozási ismereteket az egységesítés-ellenes algoritmus megvalósítására, majd a típuselméletben való alkalmazására irányuló kurzusmunkában alkalmazta.

Esemény formátuma

A célközönség a nyílt forráskódú projektek tulajdonosai, a fejlesztésükben részt venni kívánó programozók, a funkcionális programozással foglalkozó kutatók és a Haskell iránt egyszerűen szenvedélyes emberek. Idén több mint ötven nyílt forráskódú Haskell projekt fejlesztői gyűltek össze a világ minden tájáról a helyszínen - a HSR Hochschule für Technik Rapperswil -ben, hogy beszéljenek termékeikről, és felkeltsék a friss emberek érdeklődését fejlesztésük iránt.

ZuriHac: funkcionális programozás gyakorlása

Fotó a Twitterről ZuriHac

A séma nagyon egyszerű: előre meg kell írnia néhány javaslatot a projektjével kapcsolatban, és el kell küldenie a szervezőknek, akik a projekttel kapcsolatos információkat közzéteszik az esemény oldalán. Ráadásul az első napon a projektek szerzőinek harminc másodpercük van arra, hogy a színpadról nagyon röviden elmondják, mit csinálnak és mit kell tenniük. Ezután az érdeklődők megkeresik a szerzőket, és részletesen kérdeznek a feladatokról.

Saját nyitott projektjeink még nincsenek, de nagyon szeretnénk már meglévő projektekhez hozzájárulni, ezért rendszeres résztvevőként regisztráltunk. Három nap alatt két fejlesztői csoporttal dolgoztunk. Kiderült, hogy a kód és az élő kommunikáció közös tanulmányozása nagyon eredményessé teszi a projekt szerzői és közreműködői közötti interakciót – a ZuriHacnál sikerült megértenünk a számunkra új területeket, és két teljesen különböző csapatnak tudtunk segíteni, mindegyikben egy-egy feladatot teljesítve. a projektek közül.

Az értékes gyakorlat mellett számos előadás és mesterkurzus is zajlott a ZuriHacban. Két előadásra különösen emlékezünk. Ezek közül az elsőben Andrey Mokhov, a Newcastle-i Egyetemről beszélt a szelektív applikatív funktorokról – a típusok egy osztályáról, amelyeknek az aplikatív funktorok és a monádok közötti köztes kategóriát kell képezniük. Egy másik előadásban a Haskell egyik alapítója, Simon Peyton Jones arról beszélt, hogyan működik a típuskövetkeztetés a GHC fordítóprogramban.

ZuriHac: funkcionális programozás gyakorlása

Simon Peyton Jones előadása. Fotó a Twitterről ZuriHac

A hackathon során megtartott mesterkurzusokat a résztvevők képzettségi szintjétől függően három kategóriába sorolták. A projektek kidolgozásába bekapcsolódó résztvevők számára kínált feladatokat is nehézségi szinttel jelölték meg. A funkcionális programozók kicsi, de barátságos közössége örömmel fogadja soraiban az újoncokat. Andrei Mokhov és Simon Peyton Jones előadásainak megértéséhez azonban nagyon hasznos volt az egyetemen elvégzett funkcionális programozási tanfolyam.

Az eseményre a regisztráció ingyenes mind a rendszeres résztvevők, mind a projekt szerzői számára. Június elején adtuk be a részvételi jelentkezéseket, ezt követően gyorsan átkerültünk a várólistáról a visszaigazolt résztvevők közé.

És most azokról a projektekről fogunk beszélni, amelyek fejlesztésében részt vettünk.

pandoc

pandoc a szöveges dokumentumok univerzális konvertálója, valójában bármilyen formátumról bármilyenre. Például docx-ből pdf-be, vagy Markdownból MediaWikibe. Szerzője, John MacFarlane a Berkeley-i Kaliforniai Egyetem filozófiaprofesszora. Általában véve a Pandoc meglehetősen híres, és néhány barátunk meglepődött, amikor megtudta, hogy a Pandoc Haskell nyelven íródott.

ZuriHac: funkcionális programozás gyakorlása

A Pandoc által támogatott dokumentumformátumok listája. Az oldalon egy teljes grafikon is található, de ez a kép nem illik a cikkbe.

Természetesen a Pandoc nem biztosít közvetlen konverziót minden formátumpárhoz. Az ilyen sokféle átalakítás támogatására egy szabványos építészeti megoldást alkalmaznak: először a teljes dokumentumot lefordítják egy speciális belső köztes reprezentációra, majd ebből a belső ábrázolásból egy eltérő formátumú dokumentumot generálnak. A fejlesztők a belső reprezentációt „AST”-nak nevezik, ami az Abstract Syntax Tree, ill absztrakt szintaxis fa. A köztes ábrázolást nagyon egyszerűen megtekintheti: mindössze annyit kell tennie, hogy a kimeneti formátumot „natív”-ra állítja.

$ cat example.html
<h1>Hello, World!</h1>

$ pandoc -f html -t native example.html
[Header 1 ("hello-world",[],[]) [Str "Hello,",Space,Str "World!"]]

Azok az olvasók, akik legalább egy kicsit dolgoztak Haskellel, ebből a kis példából már feltételezhetik, hogy a Pandoc Haskell nyelven íródott: ennek a parancsnak a kimenete a Pandoc belső struktúráinak karakterlánc-reprezentációja, amelyet a szokásos módon készítenek. Haskellben, például a szabványos könyvtárban.

Tehát itt látható, hogy a belső reprezentáció egy rekurzív struktúra, amelynek minden belső csomópontjában van egy lista. Például a legfelső szinten van egy elem listája - az első szintű fejléc a „hello-world”,[],[] attribútumokkal. Ebben a fejlécben el van rejtve a „Hello” karakterlánc listája, amelyet egy szóköz és a „World!” karakterlánc követ.

Mint látható, a belső megjelenítés nem sokban különbözik a HTML-től. Ez egy fa, ahol minden belső csomópont ad némi információt a leszármazottai formázásáról, a levelek pedig a dokumentum tényleges tartalmát tartalmazzák.

Ha lefelé megyünk a megvalósítási szintre, akkor a teljes dokumentum adattípusa a következőképpen van meghatározva:

data Pandoc = Pandoc Meta [Block]

Itt a Block pontosan a fent említett belső csúcsok, a Meta pedig a dokumentum metainformációja, mint például a cím, a létrehozás dátuma, a szerzők – ez a különböző formátumoknál eltérő, és a Pandoc igyekszik lehetőség szerint megőrizni ezeket az információkat, amikor formátumról fordításra fordít. formátum.

Szinte minden blokk típusú konstruktor - például fejléc vagy paragrafus (bekezdés) - attribútumokat és alacsonyabb szintű csúcsok listáját veszi fel argumentumként - általában Inline. Például a Space vagy az Str Inline típusú konstruktorok, és a HTML címke is saját speciális Inline-vé válik. Nem látjuk értelmét e típusok teljes definíciójának megadni, de vegye figyelembe, hogy ez itt található itt.

Érdekes módon a Pandoc típus monoid. Ez azt jelenti, hogy van valamilyen üres dokumentum, és a dokumentumok egymásra rakhatók. Ez kényelmesen használható olvasók írásakor – tetszőleges logika segítségével részekre bonthatja a dokumentumot, mindegyiket külön-külön elemzi, majd mindent egyetlen dokumentumba állíthat össze. Ebben az esetben a metainformáció a dokumentum minden részéből egyszerre gyűjtésre kerül.

Amikor mondjuk LaTeX-ről HTML-re konvertálunk, először egy speciális, LaTeXReader nevű modul alakítja át a bemeneti dokumentumot AST-be, majd egy másik, HTMLWriter nevű modul az AST-t HTML-re. Ennek az architektúrának köszönhetően nem kell másodlagos számú konverziót írni - elég minden új formátumhoz írni a Reader és Writer parancsot, és minden lehetséges konverziópár automatikusan támogatott lesz.

Nyilvánvaló, hogy az ilyen architektúrának vannak hátrányai is, amelyeket a szoftverarchitektúra szakértői régóta jósoltak. A legjelentősebb a szintaxisfa módosításainak költsége. Ha a változás elég komoly, akkor minden olvasóban és íróban módosítania kell a kódot. Például a Pandoc fejlesztői előtt álló egyik kihívás az összetett táblázatformátumok támogatása. Most a Pandoc csak nagyon egyszerű táblázatokat tud létrehozni, fejléccel, oszlopokkal és minden cellában egy értékkel. Például a HTML colspan attribútuma egyszerűen figyelmen kívül marad. Ennek a viselkedésnek az egyik oka az egységes séma hiánya a táblák összes vagy legalább sok formátumban történő megjelenítésére – ennek megfelelően nem világos, hogy a táblákat milyen formában kell tárolni a belső reprezentációban. De még egy adott nézet kiválasztása után is meg kell változtatnia az összes olyan olvasót és írót, amely támogatja a táblázatokkal való munkát.

A Haskell nyelvet nem csak a szerzők funkcionális programozás iránti nagy szeretete miatt választották. A Haskell széleskörű szövegfeldolgozási képességeiről ismert. Ilyen például a könyvtár parsec egy olyan könyvtár, amely aktívan használja a funkcionális programozás fogalmait - monoidok, monádok, applikatív és alternatív funktorok - tetszőleges elemzők írásához. A Parsec teljes ereje látható példa a HaskellWikiből, ahol egy egyszerű kötelező programozási nyelv teljes elemzőjét elemzik. Természetesen a Parsec-et a Pandocban is aktívan használják.

Röviden leírva, a monádokat szekvenciális elemzésre használják, amikor először egy dolog következik, majd egy másik. Például ebben a példában:

whileParser :: Parser Stmt
whileParser = whiteSpace >> statement

Először meg kell számolni a szóközt, majd az utasítást - amelynek szintén Parser Stmt típusa van.

Alternatív funktorokat használnak a visszaállításra, ha az elemzés sikertelen. Például,

statement :: Parser Stmt
statement = parens statement <|> sequenceOfStmt

Azt jelenti, hogy meg kell próbálnia elolvasni a zárójelben lévő állítást, vagy meg kell próbálnia több állítást egymás után elolvasni.

Az applikatív funktorokat elsősorban a monádok parancsikonjaiként használják. Például hagyja, hogy a tok függvény beolvasson valamilyen tokent (ez a LaTeXReader valódi függvénye). Nézzük ezt a kombinációt

const <$> tok <*> tok

Két tokent olvas be egymás után, és visszaadja az elsőt.

Mindezekhez az osztályokhoz a Haskell gyönyörű szimbolikus operátorokkal rendelkezik, aminek köszönhetően a Reader programozása úgy néz ki, mint az ASCII művészet. Csak csodáld meg ezt a csodálatos kódot.

Feladataink a LaTeXReaderhez kapcsolódtak. Vaszilij feladata az mbox és a hbox parancsok támogatása volt, amelyek hasznosak a LaTeX-ben lévő csomagok írásához. Elizabeth volt felelős az epigraph parancs támogatásáért, amely lehetővé teszi epigráfok létrehozását a LaTeX dokumentumokban.

Hatrace

A UNIX-szerű operációs rendszerek gyakran alkalmazzák a ptrace rendszerhívást. Hasznos a programkörnyezetek hibakeresésében és szimulációjában, lehetővé téve a program által indított rendszerhívások nyomon követését. Például a nagyon hasznos strace segédprogram belsőleg használja a ptrace-t.

A Hatrace egy olyan könyvtár, amely felületet biztosít a Haskell ptrace-hez. A helyzet az, hogy maga a ptrace nagyon kifinomult, és meglehetősen nehéz közvetlenül használni, különösen funkcionális nyelvekből.

A Hatrace úgy fut, mint a strace indításkor, és elfogadja a hasonló érveket. Abban különbözik a strace-től, hogy ez egy olyan könyvtár is, amely egyszerűbb felületet biztosít, mint a ptrace.

A hatrace segítségével már elkaptunk egy kellemetlen hibát a GHC Haskell fordítóban - mivel rossz pillanatban megölték, hibás objektumfájlokat generál, és újraindításkor nem fordítja újra. A rendszerhívások általi szkriptelés lehetővé tette a hiba megbízható reprodukálását egy futtatás során, míg a véletlenszerű kioltások körülbelül két óra alatt reprodukálták a hibát.

Rendszerhívási felületeket adtunk a könyvtárhoz - Elizaveta a brk-t, Vaszilij pedig az mmap-ot. Munkánk eredménye alapján lehetőség nyílik ezen rendszerhívások argumentumainak egyszerűbb és pontosabb felhasználására a könyvtár használata során.

Forrás: will.com

Hozzászólás