ZuriHac: pratichiamo la programmazione funzionale.

A giugno di quest'anno, nella piccola città svizzera di Rapperswil, si è svolto per la decima volta un evento chiamato ZuriHac. Questa volta si sono riuniti più di cinquecento appassionati di Haskell, dai novizi ai padri fondatori del linguaggio. Anche se gli organizzatori definiscono questo evento un hackathon, non è una conferenza o un hackathon nel senso classico. Il suo formato è diverso da quello dei tradizionali eventi di programmazione. Abbiamo scoperto ZuriHac per pura coincidenza, abbiamo partecipato e ora ci sentiamo in dovere di raccontare di questa scoperta insolita!

ZuriHac: pratichiamo la programmazione funzionale.

Chi siamo

Questo articolo è stato scritto da due studenti del terzo anno del programma 'Matematica Applicata e Informatica' della Nizhny Novgorod State University – San Pietroburgo: Vasily Alferov ed Elizaveta Vasilenko. La nostra passione per la programmazione funzionale è iniziata entrambi con il ciclo di lezioni di D. N. Moskvin nel secondo anno dell'università. Attualmente, Vasily partecipa al programma Google Summer of Code, dove sta lavorando sull'implementazione di grafi algebrici nel linguaggio Haskell sotto la guida del team del progetto Alga. Elizaveta ha applicato le competenze acquisite nella programmazione funzionale nel suo lavoro di corso, dedicato all'implementazione di un algoritmo di anti-unificazione per poi applicarlo nella teoria dei tipi.

Formato dell'evento

Il pubblico target comprende i proprietari di progetti open source, programmatori desiderosi di contribuirvi, ricercatori della programmazione funzionale e semplici appassionati di Haskell. Quest'anno, presso l'università HSR Hochschule für Technik Rapperswil, si sono riuniti sviluppatori di oltre cinquanta progetti open source in Haskell da tutto il mondo, per presentare i loro prodotti e interessare nuove persone al loro sviluppo.

ZuriHac: pratichiamo la programmazione funzionale.

Foto da Twitter ZuriHac

Il processo è molto semplice: è necessario scrivere in anticipo alcune frasi sul proprio progetto e inviarle agli organizzatori, che pubblicheranno le informazioni sul proprio progetto sulla pagina dell'evento. Inoltre, nel primo giorno, i creatori dei progetti hanno trenta secondi per raccontare brevemente dal palco di cosa si occupano e cosa devono fare. Poi, le persone interessate cercano i creatori e fanno domande approfondite sui compiti.

Attualmente non abbiamo progetti open source propri, ma desideriamo molto contribuire a progetti esistenti, quindi ci siamo registrati come partecipanti. Nei tre giorni abbiamo lavorato con due gruppi di sviluppatori. Si scopre che studiare il codice insieme e comunicare di persona rende la collaborazione tra gli autori del progetto e i contributori molto produttiva: a ZuriHac siamo riusciti a comprendere aree a noi nuove e abbiamo potuto aiutare due team completamente diversi chiudendo un compito in ciascuno dei progetti.

Oltre a un'esperienza pratica preziosa, a ZuriHac sono state tenute diverse conferenze e workshop. Ci sono rimaste particolarmente impresse due conferenze. In una di esse, Andrey Mokhov dell'Università di Newcastle ha parlato delle funzioni applicative selettive, una classe di tipi che dovrebbe fungere da intermediario tra le funzioni applicative e le monadi. Nell'altra conferenza, uno dei fondatori di Haskell, Simon Peyton Jones, ha spiegato come funziona il sistema di inferenza dei tipi nel compilatore GHC.

ZuriHac: pratichiamo la programmazione funzionale.

Conferenza di Simon Peyton Jones. Foto da Twitter ZuriHac

I workshop tenuti durante l'hackathon erano suddivisi in tre categorie a seconda del livello di preparazione dei partecipanti. Anche i compiti proposti ai partecipanti coinvolti nello sviluppo dei progetti avevano indicazioni sul livello di difficoltà. Una comunità ristretta ma affiatata di programmatori funzionali accoglie con piacere i principianti. Tuttavia, per comprendere le conferenze di Andrey Mokhov e Simon Peyton Jones, ci è stato molto utile il corso di programmazione funzionale svolto all'università.

Per i partecipanti regolari, così come per i creatori dei progetti, la registrazione all'evento è gratuita. Abbiamo presentato la nostra domanda di partecipazione nei primi giorni di giugno e successivamente siamo stati rapidamente trasferiti dalla lista d'attesa a quella dei partecipanti confermati.

Adesso vi parleremo dei progetti a cui abbiamo partecipato nello sviluppo.

Pandoc

Pandoc è un convertitore universale di documenti di testo, di fatto – da qualsiasi formato a qualsiasi altro. Ad esempio, da docx a pdf, o da Markdown a MediaWiki. Il suo autore, John MacFarlane, è un professore di filosofia presso l'Università della California a Berkeley. In effetti, Pandoc è abbastanza noto e alcuni dei nostri conoscenti sono rimasti sorpresi quando hanno scoperto che Pandoc è scritto in Haskell.

ZuriHac: pratichiamo la programmazione funzionale.

Elenco dei formati di documenti supportati da Pandoc. Sul sito c'è anche un grafico intero, ma quell'immagine non può essere inserita nell'articolo.

Naturalmente, Pandoc non implementa una conversione diretta per ogni coppia di formati. Per supportare un così ampio numero di trasformazioni si utilizza una soluzione architettonica standard: prima l'intero documento viene convertito in una rappresentazione intermedia speciale, e poi da questa rappresentazione interna viene generato il documento in un altro formato. Gli sviluppatori chiamano questa rappresentazione interna «AST», che sta per Abstract Syntax Tree, o albero sintattico astratto. È molto semplice visualizzare la rappresentazione intermedia: basta impostare come formato di uscita «native»

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

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

I lettori che hanno lavorato anche solo un po' con Haskell possono già ipotizzare, a partire da questo piccolo esempio, che Pandoc sia scritto proprio in Haskell: l'output di questo comando è la rappresentazione delle strutture interne di Pandoc come stringa, creata in modo simile a come si fa solitamente in Haskell, ad esempio, nella libreria standard.

Quindi, qui possiamo vedere che la rappresentazione interna è una struttura ricorsiva, in cui ogni nodo interno contiene una lista. Ad esempio, al livello più alto c'è una lista con un unico elemento: un'intestazione di primo livello con attributi “hello-world”, [], []. All'interno di questa intestazione è nascosta una lista composta dalla stringa “Hello,”, uno spazio e la stringa “World!”.

Come si vede, la rappresentazione interna non si discosta molto dall'HTML. Essa rappresenta un albero, dove ogni nodo interno comunica alcune informazioni sul formato dei suoi discendenti, mentre nelle foglie si trova effettivamente il contenuto del documento.

Se scendiamo al livello di una implementazione specifica, il tipo di dati per l'intero documento è definito in questo modo:

data Pandoc = Pandoc Meta [Block]

Qui Block è esattamente i nodi interni di cui si parlava sopra, e Meta è la meta-informazione sul documento, come il titolo, la data di creazione, gli autori: per diversi formati questo è diverso, e Pandoc cerca di mantenere queste informazioni se possibile durante la conversione tra formati.

Quasi tutti i costruttori di tipo Block - ad esempio, Header o Para (paragrafo) - accettano come argomenti attributi e una lista di nodi a livello più basso - Inline, in genere. Ad esempio, Space o Str sono costruttori di tipo Inline, e anche il tag HTML
viene trasformato in un specifico Inline. Non vediamo motivo di fornire la definizione completa di questi tipi, ma notiamo che può essere visualizzata qui qui.

È interessante notare che il tipo Pandoc è un monope. Questo significa che esiste un documento vuoto e che i documenti possono essere uniti tra loro. Questo è comodo da usare quando si scrivono Reader: è possibile suddividere un documento in parti con logica arbitraria, analizzare ciascuna separatamente e poi ricomporre tutto in un unico documento. Nel frattempo, la meta-informazione verrà raccolta da tutte le parti del documento contemporaneamente.

Durante la conversione, ad esempio, da LaTeX a HTML, un modulo speciale chiamato LaTeXReader trasforma il documento d'ingresso in AST, poi un altro modulo chiamato HTMLWriter trasforma l'AST in HTML. Grazie a tale architettura non è necessario scrivere un numero quadratico di conversioni: è sufficiente scrivere un Reader e un Writer per ogni nuovo formato e tutte le possibili coppie di conversioni saranno automaticamente supportate.

È chiaro che tale architettura ha anche i suoi svantaggi, già previsti da esperti nel campo dell'architettura del software. Il più significativo è il costo delle modifiche all'albero sintattico. Se la modifica è abbastanza seria, sarà necessario modificare il codice in tutti i Reader e Writer. Ad esempio, una delle sfide per gli sviluppatori di Pandoc è il supporto di formati di tabelle complessi. Attualmente Pandoc supporta solo le tabelle più semplici, con intestazioni, colonne e valori in ciascuna cella. Ad esempio, l'attributo colspan in HTML verrà semplicemente ignorato. Una delle ragioni di questo comportamento è l'assenza di uno schema uniforme per la rappresentazione delle tabelle in tutti i formati, o almeno nella maggior parte di essi - di conseguenza, non è chiaro in quale forma debbano essere memorizzate le tabelle nella rappresentazione interna. Ma anche dopo aver scelto una rappresentazione specifica, sarà necessario modificare assolutamente tutti i Reader e Writer che gestiscono il lavoro con le tabelle.

Il linguaggio Haskell è stato scelto non solo per il grande amore degli autori per la programmazione funzionale. Haskell è conosciuto per le sue ampie capacità di elaborazione dei testi. Un esempio è la libreria parsec — una biblioteca che utilizza attivamente concetti di programmazione funzionale come monoid, monadi, funttori applicativi e alternativi per scrivere parser generici. Tutta la potenza di Parsec può essere vista in un esempio HaskellWiki, dove viene analizzato un parser completo di un semplice linguaggio di programmazione imperativo. Naturalmente, Parsec è utilizzato anche in Pandoc.

In breve, le monadi vengono utilizzate per il parsing sequenziale, dove prima avviene una cosa e poi un'altra. Ad esempio, in questo esempio:

whileParser :: Parser Stmt
whileParser = whiteSpace >> statement

Prima è necessario leggere uno spazio, e poi lo statement — che ha anch'esso il tipo Parser Stmt.

I funttori alternativi vengono utilizzati per ripristinare nel caso in cui il parsing non riesca. Ad esempio,

statement :: Parser Stmt
statement = parens statement  sequenceOfStmt

Significa che bisogna provare a leggere lo statement tra parentesi, oppure provare a leggere più statement in sequenza.

I funttori applicativi vengono utilizzati principalmente come scorciatoie per le monadi. Ad esempio, supponiamo che la funzione tok legga un certo token (questa è una funzione reale di LaTeXReader). Diamo un'occhiata a questa combinazione

const  tok  tok

Leggerà due token di seguito e restituirà il primo di essi.

Per tutte queste classi in Haskell esistono bellissimi operatori simbolici, che rendono la programmazione dei Reader simile all'arte ASCII. Guardate questo meraviglioso codice.

Le nostre attività erano legate a LaTeXReader. Il compito di Vasiliy era supportare i comandi mbox e hbox, utili per scrivere pacchetti in LaTeX. La responsabilità di Elizaveta era supportare il comando epigraph, che permette di formattare epigrafi nei documenti LaTeX.

Hatrace

Nei sistemi operativi simili a UNIX è spesso implementata la chiamata di sistema ptrace. È utile per il debugging e la simulazione degli ambienti di programmazione, permettendo di tracciare le chiamate di sistema effettuate da un programma. Ad esempio, l'utile utilità strace utilizza proprio ptrace.

Hatrace è una libreria che fornisce un'interfaccia per ptrace in Haskell. Il problema è che ptrace è abbastanza complesso e utilizzarlo direttamente può essere difficile, specialmente dai linguaggi funzionali.

Hatrace funziona all'avvio come strace e accetta argomenti simili. La sua differenza rispetto a strace è che è anche una libreria, offrendo un'interfaccia più semplice rispetto a ptrace.

Con hatrace abbiamo già catturato un fastidioso bug nel compilatore Haskell GHC — se viene terminato in un momento inappropriato, genera file oggetto errati e non li ricompila al riavvio. Lo scripting delle chiamate di sistema ha permesso di riprodurre garantito l'errore in un solo avvio, mentre terminazioni casuali riproducevano l'errore in circa due ore.

Abbiamo aggiunto interfacce per le chiamate di sistema alla libreria — Elizaveta ha aggiunto brk, mentre Vasiliy ha aggiunto mmap. A seguito del nostro lavoro, ora è possibile utilizzare più semplicemente e con precisione gli argomenti di queste chiamate di sistema quando si usa la libreria.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS 🔥 Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS | ProHoster