Im Juni dieses Jahres fand in der kleinen Schweizer Stadt Rapperswil bereits zum zehnten Mal eine Veranstaltung mit dem Namen . Dieses Mal versammelten sich mehr als fĂŒnfhundert Haskell-Enthusiasten, von AnfĂ€ngern bis hin zu den GrĂŒndervĂ€tern der Sprache. Obwohl die Organisatoren diese Veranstaltung als Hackathon bezeichnen, ist sie dennoch keine Konferenz oder ein traditioneller Hackathon im klassischen Sinne. Ihr Format unterscheidet sich von den traditionellen Programmierveranstaltungen. Wir erfuhren durch einen glĂŒcklichen Zufall von ZuriHac, nahmen teil und fĂŒhlen uns jetzt verpflichtet, ĂŒber diese auĂergewöhnliche Entdeckung zu berichten!

Ăber uns
Dieser Artikel wurde von zwei Studierenden im dritten Jahr des Studiengangs "Angewandte Mathematik und Informatik" an der Nationalen ForschungsuniversitĂ€t Higher School of Economics â Sankt Petersburg verfasst: Wasilij Alferow und Elizaveta Vasilenko. Unsere Begeisterung fĂŒr funktionale Programmierung begann fĂŒr uns beide mit einer Vorlesungsreihe von D. N. Moskvin im zweiten Studienjahr. Momentan nimmt Wasilij am Google Summer of Code-Programm teil, in dessen Rahmen er die Implementierung algebraischer Graphen in der Programmiersprache Haskell unter der Leitung des Projektteams durchfĂŒhrt. . Elisabeth hat die erlernten FĂ€higkeiten im funktionalen Programmieren in ihrer Abschlussarbeit angewendet, die sich mit der Implementierung eines Anti-Unifikationsalgorithmus und dessen Anwendung in der Typentheorie befasst.
Veranstaltungsformat
Die Zielgruppe besteht aus Projektleitern von Open-Source-Projekten, Programmierern, die an deren Entwicklung teilnehmen möchten, Forschern im Bereich funktionales Programmieren und einfach Haskell-begeisterten Personen. In diesem Jahr versammelten sich im Veranstaltungsort â der HSR Hochschule fĂŒr Technik Rapperswil â Entwickler aus mehr als fĂŒnfzig Open-Source-Projekten in Haskell aus der ganzen Welt, um ĂŒber ihre Produkte zu berichten und neue Interessenten fĂŒr deren Weiterentwicklung zu gewinnen.

Foto von Twitter
Das Schema ist ganz einfach: Man muss im Voraus ein paar SĂ€tze ĂŒber sein Projekt schreiben und diese an die Organisatoren senden, die die Informationen ĂŒber Ihr Projekt auf der Event-Seite veröffentlichen. AuĂerdem haben die Projektverantwortlichen am ersten Tag jeweils dreiĂig Sekunden Zeit, um von der BĂŒhne aus ganz kurz zu erklĂ€ren, woran sie arbeiten und was getan werden muss. Danach suchen interessierte Personen die Autoren auf und fragen ausfĂŒhrlich nach den Aufgaben.
Wir haben derzeit keine eigenen offenen Projekte, möchten aber sehr gerne zu bestehenden beitragen, daher haben wir uns als normale Teilnehmer registriert. WĂ€hrend der drei Tage haben wir mit zwei Entwicklergruppen gearbeitet. Es hat sich herausgestellt, dass das gemeinsame Lernen von Code und persönliche Interaktion die Zusammenarbeit zwischen Projektverantwortlichen und Mitwirkenden sehr produktiv macht â bei ZuriHac konnten wir uns in fĂŒr uns neue Bereiche einarbeiten und zwei ganz unterschiedlichen Teams helfen, indem wir in jedem der Projekte eine Aufgabe erledigt haben.
Neben wertvollen praktischen Erfahrungen wurden auf der ZuriHac auch mehrere VortrĂ€ge und Workshops gehalten. Besonders im GedĂ€chtnis geblieben sind uns zwei VortrĂ€ge. Im ersten sprach Andrey Mokhov von der UniversitĂ€t Newcastle ĂŒber selektive anwendbare Funktoren â eine Typpalette, die als Bindeglied zwischen anwendbaren Funktoren und Monaden fungieren soll. In dem anderen Vortrag erzĂ€hlte einer der BegrĂŒnder von Haskell, Simon Peyton Jones, wie der Typausdruck im GHC-Compiler funktioniert.

Vortrag von Simon Peyton Jones. Foto von Twitter
Die wĂ€hrend des Hackathons durchgefĂŒhrten Workshops wurden in drei Kategorien unterteilt, je nach Erfahrungsgrad der Teilnehmer. Die Aufgaben, die den Teilnehmern, die an der Entwicklung von Projekten beteiligt sind, angeboten wurden, hatten ebenfalls Schwierigkeitsstufen. Die kleine, aber einladende Gemeinschaft der funktionalen Programmierer heiĂt Neulinge mit Freude willkommen. Um die VortrĂ€ge von Andrey Mokhov und Simon Peyton Jones zu verstehen, war jedoch der im Studium absolvierte Kurs ĂŒber funktionale Programmierung sehr hilfreich.
Sowohl fĂŒr regulĂ€re Teilnehmer als auch fĂŒr Projektverfasser ist die Registrierung fĂŒr die Veranstaltung kostenlos. Wir haben Anfang Juni AntrĂ€ge auf Teilnahme eingereicht und wurden danach relativ schnell von der Warteliste in die Liste der bestĂ€tigten Teilnehmer ĂŒberfĂŒhrt.
Nun möchten wir Ihnen die Projekte vorstellen, an deren Entwicklung wir beteiligt waren.
Pandoc
â ist ein universeller Umwandler fĂŒr Textdokumente, praktisch von jedem Format in jedes andere. Zum Beispiel von docx in pdf oder von Markdown in MediaWiki. Sein Autor, John MacFarlane, ist Professor fĂŒr Philosophie an der University of California in Berkeley. Pandoc ist allgemein recht bekannt, und einige unserer Bekannten waren ĂŒberrascht zu erfahren, dass Pandoc in Haskell geschrieben ist.

Hier ist eine Liste der von Pandoc unterstĂŒtzten Dokumentenformate. Auf der Website gibt es auch ein vollstĂ€ndiges Diagramm, aber dieses Bild passt nicht in den Artikel.
NatĂŒrlich bietet Pandoc keine direkte Konvertierung fĂŒr jedes Format-Paar an. FĂŒr die UnterstĂŒtzung eines so umfangreichen Spektrums von Konvertierungen wird ein standardmĂ€Ăiges architektonisches Verfahren verwendet: Zuerst wird das gesamte Dokument in eine spezielle interne Zwischenrepresentation ĂŒbersetzt, und anschlieĂend wird auf Basis dieser internen Darstellung ein Dokument im gewĂŒnschten Format generiert. Diese interne Darstellung nennen die Entwickler âASTâ, was fĂŒr Abstract Syntax Tree steht, oder . Um sich die ZwischenreprĂ€sentation anzusehen, ist es ganz einfach: Man muss lediglich das Ausgabeformat auf ânativeâ setzen.
$ cat example.html
<h1>Hallo, Welt!</h1>
$ pandoc -f html -t native example.html
[Header 1 ("hello-world",[],[]) [Str "Hallo,",Space,Str "Welt!"]]
Leser, die auch nur ein wenig mit Haskell gearbeitet haben, können aus diesem kleinen Beispiel schlieĂen, dass Pandoc tatsĂ€chlich in Haskell geschrieben ist: Die Ausgabe dieses Befehls ist eine Darstellung der internen Strukturen von Pandoc in Form eines Strings, Ă€hnlich dem, wie es in Haskell normalerweise in der Standardbibliothek gemacht wird.
Hier kann man sehen, dass die interne Darstellung eine rekursive Struktur darstellt, bei der jeder innere Knoten eine Liste enthĂ€lt. Beispielsweise liegt auf der obersten Ebene eine Liste mit einem Element â einem ersten Header mit den Attributen âhello-worldâ,[],[]. Innerhalb dieses Headers verbirgt sich eine Liste, die aus der Zeichenkette âHello,â, einem Leerzeichen und der Zeichenkette âWorld!â besteht.
Die interne Darstellung unterscheidet sich nicht stark von HTML. Sie stellt einen Baum dar, in dem jeder innere Knoten Informationen ĂŒber das Formatieren seiner Nachfolger bereitstellt, wĂ€hrend die BlĂ€tter tatsĂ€chlich den Inhalt des Dokuments enthalten.
Wenn man auf die Stufe einer konkreten Implementierung heruntergeht, wird der Datentyp fĂŒr das gesamte Dokument so definiert:
data Pandoc = Pandoc Meta [Block]Hier ist Block genau das, was die vorher erwĂ€hnten inneren Knoten sind, wĂ€hrend Meta die Metainformationen ĂŒber das Dokument enthĂ€lt, wie Titel, Erstellungsdatum, Autoren â je nach Format ist dies unterschiedlich, und Pandoc versucht, solche Informationen beim Konvertieren von Format zu Format so gut wie möglich zu erhalten.
Fast alle Block-Typen, wie Header oder Para (Absatz), akzeptieren Attribute und eine Liste von tiefer eingestuften Knoten als Argumente â in der Regel Inline. Zum Beispiel sind Space oder Str Konstruktoren vom Typ Inline, und auch das HTML-Tag wird in einen speziellen Inline-Konstruktor umgewandelt. Wir halten es nicht fĂŒr sinnvoll, eine vollstĂ€ndige Definition dieser Typen zu geben, aber man kann sie hier einsehen. .
Interessanterweise ist der Typ Pandoc ein Monoid. Das bedeutet, dass es ein leeres Dokument gibt und dass Dokumente miteinander kombiniert werden können. Dies ist besonders nĂŒtzlich beim Schreiben von Readern â man kann ein Dokument nach einer beliebigen Logik in Teile aufteilen, jede einzeln parsen und schlieĂlich alles wieder zu einem einzigen Dokument zusammenfĂŒgen. Dabei wird die Metainformation sofort aus allen Teilen des Dokuments gesammelt.
Bei der Konvertierung, beispielsweise von LaTeX nach HTML, wandelt zunĂ€chst ein spezielles Modul namens LaTeXReader das Eingabedokument in einen AST um. AnschlieĂend konvertiert ein weiteres Modul, der HTMLWriter, den AST in HTML. Dank dieser Architektur ist es nicht notwendig, eine quadratische Anzahl an Konvertierungen zu schreiben â es genĂŒgt, fĂŒr jedes neue Format einen Reader und einen Writer zu entwickeln, und alle möglichen Konvertierungspaare werden automatisch unterstĂŒtzt.
Es ist offensichtlich, dass eine solche Architektur auch ihre Nachteile hat, die bereits von Fachleuten im Bereich der Softwarearchitektur vorhergesagt wurden. Der bedeutendste Nachteil ist die Kosten fĂŒr Ănderungen am Syntaxbaum. Wenn die Ănderung erheblich ist, muss der Code in allen Readern und Writern angepasst werden. Zum Beispiel steht eine der Herausforderungen fĂŒr die Entwickler von Pandoc darin, komplexe Tabellenformate zu unterstĂŒtzen. Derzeit kann Pandoc nur einfache Tabellen mit einer Ăberschrift, Spalten und Werten in jeder Zelle verarbeiten. Zum Beispiel wird das Attribut colspan in HTML einfach ignoriert. Einer der GrĂŒnde fĂŒr dieses Verhalten ist das Fehlen eines einheitlichen Schemas zur Darstellung von Tabellen in allen oder zumindest vielen Formaten â entsprechend ist unklar, in welcher Form Tabellen in der internen Darstellung gespeichert werden mĂŒssen. Aber auch nach der Wahl einer spezifischen Darstellung mĂŒssen alle Reader und Writer, die die Arbeit mit Tabellen unterstĂŒtzen, vollstĂ€ndig geĂ€ndert werden.
Die Programmiersprache Haskell wurde nicht nur aus groĂer Liebe der Autoren zur funktionalen Programmierung gewĂ€hlt. Haskell ist bekannt fĂŒr seine umfangreichen Möglichkeiten zur Textverarbeitung. Ein Beispiel dafĂŒr ist die Bibliothek â eine Bibliothek, die aktiv Konzepte der funktionalen Programmierung â Monoid, Monad, Applikative und alternative Funktoren â zur Erstellung beliebiger Parser nutzt. Die gesamte LeistungsfĂ€higkeit von Parsec wird deutlich in mit HaskellWiki, wo ein vollstĂ€ndiger Parser einer einfachen imperativen Programmiersprache behandelt wird. NatĂŒrlich wird Parsec auch aktiv in Pandoc verwendet.
Kurz gesagt, Monaden werden fĂŒr sequenzielles Parsen verwendet, wobei zuerst das eine und dann das andere kommt. Zum Beispiel in folgendem Beispiel:
whileParser :: Parser Stmt
whileParser = whiteSpace >> statementZuerst muss der Leerraum gelesen werden, gefolgt von der Anweisung â die ebenfalls den Typ Parser Stmt hat.
Alternative Funktoren werden verwendet, um im Falle eines Parsingfehlers zurĂŒckzurollen. Zum Beispiel,
statement :: Parser Stmt
statement = parens statement sequenceOfStmtBedeutet, dass entweder versucht werden muss, die Anweisung in Klammern zu lesen, oder es nacheinander mehrere Anweisungen gelesen werden.
Applikative Funktoren werden hauptsĂ€chlich als AbkĂŒrzungen fĂŒr Monaden verwendet. Zum Beispiel sei die Funktion tok, die ein Token liest (das ist eine echte Funktion aus LaTeXReader). Schauen wir uns eine solche Kombination an.
const (tok tokSie wird zwei Tokens nacheinander lesen und das erste zurĂŒckgeben.
FĂŒr all diese Klassen gibt es in Haskell elegante symbolische Operatoren, die das Programmieren von Readern wie ASCII-Kunst erscheinen lassen. Schauen Sie sich nur diesen beeindruckenden Code an.
Unsere Aufgaben waren mit LaTeXReader verbunden. Vasiliy war fĂŒr die UnterstĂŒtzung der Befehle mbox und hbox zustĂ€ndig, die beim Schreiben von Paketen in LaTeX nĂŒtzlich sind. Elizabeth war verantwortlich fĂŒr die UnterstĂŒtzung des Befehls epigraph, der die Gestaltung von Epigraphen in LaTeX-Dokumenten ermöglicht.
Hatrace
In UNIX-Ă€hnlichen Betriebssystemen wird hĂ€ufig der Systemaufruf ptrace implementiert. Er ist nĂŒtzlich beim Debuggen und Simulieren von Programmumgebungen, indem er die Systemaufrufe nachverfolgt, die ein Programm macht. Zum Beispiel verwendet das sehr nĂŒtzliche Tool strace genau ptrace.
Hatrace â eine Bibliothek, die eine Schnittstelle fĂŒr ptrace in Haskell bereitstellt. Das Besondere ist, dass ptrace sehr komplex ist und die direkte Nutzung ziemlich schwierig, insbesondere aus funktionalen Sprachen, erfolgt.
Hatrace funktioniert beim Start wie strace und akzeptiert Àhnliche Argumente. Der Unterschied zu strace besteht darin, dass es auch eine Bibliothek ist, die eine einfachere Schnittstelle als nur ptrace bietet.
Mit Hatrace wurde bereits ein unangenehmer Fehler im Haskell-Compiler GHC gefunden â wenn er zu einem ungĂŒnstigen Zeitpunkt gestoppt wird, generiert er fehlerhafte Objektdateien und kompiliert diese beim Neustart nicht erneut. Das Skripting von Systemaufrufen hat es ermöglicht, den Fehler bei einem einzigen Lauf zuverlĂ€ssig zu reproduzieren, wenn zufĂ€llige Stopps den Fehler etwa alle zwei Stunden reproduzierten.
Wir haben der Bibliothek Schnittstellen fĂŒr Systemaufrufe hinzugefĂŒgt â Elizaveta fĂŒgte brk hinzu, wĂ€hrend Vasiliy mmap implementierte. Dank unserer Arbeit können die Argumente dieser Systemaufrufe einfacher und prĂ€ziser genutzt werden, wenn die Bibliothek verwendet wird.
Quelle: habr.com
