Haskell Summer of Code 2017: Last Mile for `cabal new-build`: first and last status update

comments

Time flies! The Haskell Summer of Code is over, and this is my first and last status update. Last in the HSoC, but not in the project, as you’ll see.

My goal was to bring new-build to a usable state, to eventually replace the old commands.

What has been done

My original proposal was way too optimistic. Of the many secondary and optional goals I planned, I’ve reached zero of them.

Fortunately they were, as I wrote, secondary. new-build was and is a work in progress, but now it’s close to completion.

Here’s a summary of what I did:

#3638: new-run, new-test, new-bench, new-exec

The most important goal of the project was to reach feature parity with old-build.

  • new-run is now fully functional
  • new-test and new-bench work, except from some rough edges (like the ability to pass arguments to tests)
  • new-exec has always been kind of an hack and we discussed a lot about it. Environment files helped a lot, and you should check them out!

With these commands, new-build only lacks new-install.

Data-files

Data-files are additional files to be included in a package distribution (be it a sdist, a debian package or the store itself). They are used when including the data in the executable itself (eg. with a literal string or even a picture using file-embed) is not feasible or not practical.

The path to the data-files is hardcoded at compile-time (the --datadir flag), and by default it is set to the store (where the majority of packages will reside). For this reason, when using an inplace-built package, datadir resolved to a non-existing directory.

Fortunately, datadir can be overridden with an environment variable, which is now properly set by new-run.

If your project includes data-files, now you can use new-run and it should work without problems.

new-install …almost

This is the biggest command, because it actually handles four cases:

  • nonlocal exes (cabal new-install pandoc; pandoc file.md)
  • nonlocal libs (cabal new-install lens; ghci; import Control.Lens)
  • local exes (cabal new-install in a project)
  • local libs (cabal new-install in a project, but for libraries, partially solved by environment files )

The first one, which allows the installation of programs from hackage, and is probably the most used one (eg. cabal new-install pandoc), is almost complete (needs some cleanup but it works).

The difference with old-install is that executables will be installed in the store and symlinked to ~/.cabal/bin or equivalent.

This raises the problem of garbage collection: deleting the symlink leaves the executable and all of its dependencies in the store. In the future, a cabal garbage-collect command will track the symlinks and automatically clean the store.

How to try it

Cabal HEAD should always build and should be fairly stable. If you want to try the new features just run:

    cabal get -s cabal-install
    cd cabal-install*

and then build/install it with cabal install or cabal sandbox init + cabal install or cabal new-build.

What remains to do

90% of the work was done, now there’s the other 90%.

The HSoC is now complete, but new-build cannot replace the old interface yet: a few essential features are missing, and –now that I’m more familiar with the cabal codebase– I plan to work on some of them even outside of the HSoC period. 1

a small mountain, and a big mountain
`new-install` is the one just to the right

Finishing new-install

One point done, three to go.

There is a design concept, but there are a lot of details to figure out, for the libraries in particular.

The aforementioned garbage-collect

The store can grow rapidly and reach several GB in size, so we need a way to clean it up without influencing any built or installed package.

Again, there is a design concept on the issue page.

Flags for package maintainers

Before replacing old-build, we need to be sure that package maintainers have still a way to control the location of binaries and data-files.

Difficulties I encountered

Big codebase

    > cloc cabal
    [...]
    Language          files      blank    comment       code
    --------------------------------------------------------
    Haskell            1273      24897      28127     120096

Cabal is big. Big project, big functions, big types, big everything.

My biggest Haskell project before HSoC was two orders of magnitude smaller, and this was my first impact with a real-world project developed by a team during an extended period of time.

an Interstellar meme
[ORGAN INTENSIFIES]

Haskell’s strong types helped me a lot here. When I was working on new-bench, I just “followed the types”, and everything clicked on the first try, as the legends say.

Lack of documentation

The cabal bus factor is somewhat low.

Some parts of the codebase are completely devoid of comments, and we lack an overview of the codebase, some document which describes how cabal works and where to find certain parts.

Few mysterious entities, known as cabal devs, are the precious holders of such arcane knowledge, and to learn from them one must prove himself worthy of it by sheer pinging-perseverance on #hackage

…fortunately they are always happy to give some pointers to newcomers :) .

dcoutts as a sorcerer on cabal as a creature
In this rare photography we can see dcoutts (top) while he invokes a nix-style build on cabal (below)

Moreover, the documentation is improving. The undocumented parts are mostly old code, and there is an ongoing effort to cover that too.

And again, Haskell’s types come to the rescue! The type always enhances and often replaces the documentation in a more expressive way.

Git

I now see that my git practices weren’t the best…

A messy git history

well, not at this level, but...

Credit: xkcd (CC BY-NC 2.5)

I had to learn git the right way.

Coding alone is different than doing it in a team. Until now I almost never had to deal with conflicts2, and I almost always worked only on master.

In the cabal repo, lots of features get merged very often (well, more often than in a single user repo anyway), so it’s easy to get a conflict. The history has to be kept clean, so I finally had to learn how to rebase properly too.

This didn’t always go well. In an attempt to rebase an old branch I accidentally created a convoluted merge graph, almost impossible to disentangle.

A very messy git history
Welp.

Oh well, we learn from our errors.

I also had to exercise my multitasking skills by working on different branches. While the tests for one branch were running, I could write the docs for another command. Or two. The tests take a long time.

Which takes us to…

Continuous Integration

There’s 4 hours worth of tests, from ghc 7.6 (cabal has a support window of five years) to 8.2. And there are the FTP and the AMP in the middle.

Two stick figures play with swords while ci runs
Credit: xkcd (CC BY-NC 2.5)

But this is a plus! Apart from the many sword fights, the tests helped me catch a lot of bugs before even committing them. Now I use ci for many of my personal projects too.

Project planning and organization

I never had to do a fixed project on a strict schedule, and Daniel helped me a lot here. If it wasn’t for him I’ll probably be trying to fix mostly pointless bugs now. Planning time is not wasted time!

Beware the paths!

One little thing: cabal now uses a slightly different path for built binaries.

My build command used the old one, and I wasted 1 hour or so trying to figure out why my debug statements weren’t printing anything.

This happened two three times.

You only need to worry about this if you use both pre- and post-2.0 new-build in the same project though. While pre-2.0 puts the executables in dist-newstyle/build/package-id/build/exe/exe, post-2.0 puts them in dist-newstyle/build/os/compiler/package-id/build/exe/exe.

Good things

Now I use new-build for all my Haskell projects!

Obviously I eat my own dog food now. And I like it.

In the next weeks I’ll write a post about it, specifically about how to integrate new-build and vim.

HSoC itself

The Haskell Summer of Code has been a wonderful experience, and I recommend it to every student who is reading this!

It taught me so much, and I loved being able to work on an open source project as widely used as cabal (well, in the Haskell ecosystem at least :-P ).

The Community

And last but absolutely not least, the #hackage community was always very helpful and friendly, offering constructive criticism and involving me in related projects.

Acknowledgments

I’d like to thank the Haskell community, always friendly and striving for knowledge; the organizers and sponsors, which made possible this HSoC; and most of all the #hackage folks: Daniel, my mentor, who helped me a lot when I was lost in the code or when I needed to plan, Duncan “dcoutts”, Herbert “hvr”, Mikhail “refold”, Edward “ezyang”, alanz, merijn, phadej, cocreature, and any others who helped me along the way.

Upcoming posts

  • My new-build dev setup
  • The structure of cabal (I hope)
  • Some more technical challenges I encountered
  1. I’m beginning to suspect that the Haskell Summer of Code is just an evil scheme to lure some poor students to become permanent contributors to the Haskell ecosystem ;) 

  2. Well, even when i did… 

Catene di Markov, letteratura e musica

comments

Frugando nella cartella dei miei vecchi progetti ho ritrovato un esperimento che ho fatto circa un anno fa (e che avrei dovuto postare) sulle catene di Markov.

Data una sequenza di oggetti (parole, numeri, note…) si può determinare per ogni coppia di oggetti x e y la probabilità che x sia seguito da y. Da questo insieme di probabilità si può ricavare una sequenza casuale “pesata” che mantiene le stesse probabilità.

Applicando questo processo a una sequenza di parole si ottengono dei risultati …interessanti.

Letteratura, testi di canzoni…

  • La Divina Commedia:

Oh terreni animali! oh felice te e ‘l maestro accorto gridò: “Se’ tu tenesti ne ‘nfiora la milizia santa suora mia sorte, e io te non si tacque, ciò per la qual mi ‘nsegni, e io udi’ cantando, quelli allotta, pudica che verso li uomini esser largo; ma giù la scabbia, come i rami schianta, abbatte e ‘l frate: “Io udi’ ne seguì fin si fé volar sù pinti”. Allor si ristora”.
Né prima lo gran manto; e vanno scoperti de l’ampia gola fiera. Vita bestial mi rimorse”. “Drizza le giostre grame. Allor puose con li giusti occhi al vivo assai che tossio al sangue, oltre mi vieta di cozzo in su la qual si tranquilla e la fortuna o testimonio, rècati a l’acqua perigliosa e disse: “O Mantoano, io d’un sorriso, ella esce del suo fattore non furon porti. Mentre che concepe e simile a parlar mi travagliava, e non par sì ver la pioggia continua converte in loco de l’alta carità, che che cuopre ‘l duca mio, ma chi nel trono che ‘l pozzo che il senso inganna, non lassa; misericordia chiesi e piedi stante. Taide è, la terra sì ch’elli eran già s’imbiancava al mio allor gelato in sù condotto, li alti spaldi.

  • I Promessi Sposi:

Subito dopo aver pregato frequentemente d’intervenire in un certo tempo, delle meglio, quella moltitudine? Si chiuse da quella sua fama ch’egli medesimo aveva detta quella benedetta, per otto o gli scherni e dandogli un’occhiata a quel silenzio, senza venire a piacer suo, insieme alla parete accanto a passi fuori non di chiaro che teme e cambiandosi le braccia nelle relazioni dell’autorità che lasciavano il grano. Ora fammi un povero forno; e volevi far le margini de’ calzoni il padrone, era, in qualche lume sul bergamasco; ma un bell’onore, senza fare buona volontà di sedizione. - Va innanzi; rallenta quelle cause generali, di concerto; e l’accompagnavano con voce fiacca e avvicinarsi troppo; perché, ogni discorso qualunque. - le mise un momento in essi, parlava con Perpetua, fece scorrer liberi il dirlo, il momento immobile sur un momento sul carro di non è un buco nell’acqua; anzi appena quanto basti a un nome e una voce, annunziando che allora le dispiaceva a me tocca a quattro dal canto di fuori; se non fu un gentiluomo. Al suo nemico, l’alterazione di non si concluse tra le frasi, né all’altro. Che se dicesse: ah! la persona di grand’ombre. Si voltò per passare un lungo bicchiere un po’ più che replicare il caso di pilastri e d’invidia di spedire un uomo il quale, dal soggetto di panca, sotto gli altri due? che facevano a divorar la casa natìa, dove, non era finita; ma mise l’acqua s’andava verso quella che il vento in volto, e mille volte giovine contadina come eroi, ubbidienti come ognuno s’avviasse.

  • Il mio preferito, il capitolo su Kant di un libro di filosofia:

Invece, ci dicono cose come appaiono e da trattare gli zoccoli e antitesi: nel 1781, in termini finalistici. L’ammissione provvisoria del miglior mondo esterno, ma non la concatenazione e l’imperativo categorico, si adattino in Hume di noi; muovendo dalla formulazione di là di allora, dalle categorie; in quanto tale collegamento che non potevo conoscere il bruciore è un sentimento su Dio (unità e ciò a Newton: riprendendo l’immagine della legge, è solo il tempo sono veri ancor prima volta a posteriori sono pure della coesistenza fra loro. Così nasce appunto sull’esperienza: si può mai che separa mondo fisico, non possono spingere tali forme. Siamo autorizzati a disposizione, il termine egli operi in vacanza ai dati dell’esperienza so che si può essere riempita di sostanza. Tuttavia, Kant risponde a vero che saranno tali ‘gradi’. Il pietismo è illegittima, secondo Kant, pur essendo concetti permette di Newton, servendosi, nella Critica della forma che il bene. Kant con le cose nè particolari , Kant distinguerà tra loro a priori ne consegue che se derivino dall’esperienza (e in determinati dall’applicazione delle forme non vi saranno le leggi che 5+7 non causi la legge morale cristiana, giungendo a suo scritto le cose (pensa, percepisce, ecc) ed è necessario (modalità), e del sigillo (l’oggetto) impressole. Questa seconda che siamo fenomeni (unità), ma se invece faceva con la categorie . Ecco perchè più sistematica di un ‘fine’, uno svago delle specifiche categorie conoscitive l’abbia posto in quanto disinteressato, non derivati dall’applicazione delle categorie stesse, infatti, si arriva ad essere qualcosa di considerata a caso.

È praticamente indistinguibile da un vero testo di filosofia1.

  • Su richiesta, varie di Vasco rossi:

senza tempo oggi voglio correre e ho tempo e ogni volta che era una sorpresa che sono coerente e da qui… qui non si vede quello che mi è buia e va bene così… senza tempo Vivere Anche se sei chiara come perder tempo Vivere Eeeh e va bene così… senza parole e ogni volta che torna sera mi è facile sentirsi da qui… “non le tue Lucky Strike e ho cercato di star meglio Vivere E ogni volta che ritorno ogni volta che mi sento solo “fesserie”… E da qui… e va bene così… senza parole e ci sei assorta dei tuoi problemi, dei tuoi problemi, dei tuoi pensieri… Ti vesti svogliatamente, non si prova non ho più quelle estati lì” “quelle estati lì” Qui la notte è logico cambiare mille volte idea ed è importante ogni volta che viene in faccia pulita cammini per me ogni volta che sogni. Qualche volta quando… E poi pensare che tu non si può spiegare qui hai “la scusa” che torna sera mi prende la televisione mi rubi l’amore ma poi ho capito che sembrano piu’ capaci guarda quante cose e da qui…

  • L’ignoranza mista alla sapienza, varie de Il Pagante + La Divina Commedia:

Lasciai la santa lalalala sempre presa bene lalalala e domani Minchia frate, faccio after per me parlar non par surger nuovo fummo al quale aspetta tanto rubesto, che si scrivon tutti con questa soma. Al fine col DonPero Il Pagante è pettine La gente che merda lordo, che sua madre ebber li organi suoi persecutori. “Dai Johnny, non puoi tu dimandi, o quando usciamo dai locali Everybody tutti fatti… Ba, ba, balzaaa Tutti pronti per andar ti maravigliar s’io ancor la vorare in pista sboccio il Disaronno e quai prima che lutto, madre, ch’è suggello a veder se Brunetto Latino un altro vello ritornerò poeta, e Stazio la fila ma per ch’i’ ho portato dei miei amici ultra!

  • Licenza GNU GPL

If your program is conditioned on you with specific operating system (if authorized by its parts, regardless of this License is to deny users access to provide support for the product. A separable portion of this is a work as your rights of the work results from any third party means the Corresponding Source includes a durable physical distribution medium, is a covered work with the continued functioning of Sections 15 and prominently visible feature that the particular programming language, one or any price or distribution medium), accompanied by the third party that users beyond what you may be stated conditions are referring to run, modify the product is a covered work in spirit to copy that you may remove that any additional or school, if neither you under section 4 and (b) permanently, if you also meet all notices stating that material) supplement the covered by a patent license or installed in a network server at your license is either (1) assert copyright holder who have actual knowledge that, without modification), making or other charge for publicity purposes of what it or from you grant rights with a license from the GNU General Public License into proprietary programs. If the covered work in the status of it, and how to receive the only way in accord with such as well. To “grant” such abuse occurs in a third parties’ legal notices stating that there is either of previous paragraph, plus a free, copyleft license fee, you waive any part of works.

È sorprendente il fatto che, nonostante non sia stata definita alcuna regola di costruzionde del periodo, molte delle frasi generate hanno un senso quasi compiuto. Per avere risultati migliori sarebbe utile considerare due parole per generare la successiva, ma sono più lazy di Haskell, quindi sarà per un’altra volta.

Musica!

Usare un .midi? Naaaaah, troppo mainstream.
Ecco invece il remix di Aerodynamic in formato beep generata a partire da un file trovato su un blog:

Aerodynamic_beep_remix_by_DJ_Markov.sh

Qui al contrario i risultati sono pessimi. La musica, essendo composta da un numero ben inferiore di elementi distinti (le note), varia in modo molto più imprevedibile (relativamente all’elemento precedente). Anche qui probabilmente si potrebbe ottenere qualcosa di migliore analizzando le battute, invece che le singole note, di una grande mole di composizioni. Che io non ho.

Chi ha in mente qualche testo da analizzare lo scriva pure nei commenti, i risultati sono sempre spassosi!

  1. :^) 

Traduttore di codice morse in Haskell

comments

Qualche tempo fa ho trovato su /r/programming questo vecchio thread con un interessante esercizio di programmazione. La richiesta era in apparenza molto semplice:

Chi sa scrivere il più piccolo/pulito/intelligente traduttore di Codice Morse?

Per chi non lo sapesse il Codice Morse è un alfabeto composto di soli punti e linee, utilizzato per inviare messaggi a distanza tramite luce, suono o simili mantenendoli umanamente comprensibili.

Il Codice Morse

L’idea più semplice

La soluzione più semplice e intuitiva è ovviamente quella di associare a ogni sequenza di punti e linee la lettera dell’alfabeto corrispondente usando un dizionario o simili:

#pseudocodice:
".-"   = 'a'
"-..." = 'b'
"-.-." = 'c'
#...eccetera

Hm. Funziona, ma non è né corto né “intelligente”. Si può fare di meglio!

Strutturare i dati

Come si possono esprimere questi dati in maniera più concisa? Beh, una lettera in morse è composta da un punto o una linea, che può essere o non essere seguito da un altro punto o linea e così via. Si può provare a dividere le lettere su questa base!

In base al primo simbolo:

punto            linea
eishvufarlwpj    tndbxkcymgzqo

In base al secondo:

punto              linea
eishvufarlwpj      tndbxkcymgzqo
punto    linea     punto     linea
ishvuf   arlwpj    ndbxkcy   mgzqo

A ogni passaggio la struttura si dirama… come in un albero! Infatti il codice morse può essere rappresentato da un albero come questo: 1

Codice morse in una struttura ad albero

Per ogni simbolo componente la lettera si scende a sinistra nel caso di un punto o a destra nel caso di una linea, fino ad arrivare nella foglia che conterrà la traduzione.

Come esprimere tutto questo in un linguaggio di programmazione? Si può creare un tipo di dato (come è già stato fatto qui)…
…Oppure comprimere tutto l’albero in un’unica stringa! 2

Se per ogni foglia si scrive la lettera corrispondente seguita da due stringhe di lunghezza uguale contenenti i due rami collegati a quella foglia (rappresentati con lo stesso metodo) 3 si ottiene " eishvuf?arl?wpjtndbxkcymgzqo??". I punti di domanda sono dei segnaposto che indicano la mancanza di una lettera corrispondente a quella sequenza (le caselle dell’albero vuote).

Il codice

Ho pensato di implementare la soluziona a questo problema in Haskell: un linguaggio funzionale puro in cui mi sto cimentando che probabilmente apparirà molto spesso in queste pagine… Non mi dilungo a descriverlo ulteriormente, dato che esistono già numerose risorse al riguardo4.

Codice:

Il funzionamento è piuttosto semplice: viene applicato un fold alla lettera in morse, percorrendo man mano i punti e le linee. L’accumulatore è l’albero descritto prima e la funzione non fa altro che dividere in due la stringa e scegliere la prima o la seconda metà a seconda del simbolo (punto o linea). Terminato il fold, la foglia corrente (quindi la testa della stringa) sarà la lettera tradotta.

Escludendo gli import, l’esplicitazione dei tipi e la dichiarazione separata di half il codice è composto solo da 5 righe per la decodifica (che era l’obiettivo principale) e 8 per la codifica. È un ottimo risultato considerando che l’unico codice più corto è quello in python, che però non è altrettanto leggibile

  1. Artwork by: mia sorella (R) (TM) 

  2. Lo so, può sembrare una complicazione in più, ma alla fine porta a un codice più corto e comunque leggibile (come richiesto nel thread) 

  3. Si può immaginare di ripiegare l’albero trascinando la cima in basso a sinistra 

  4. Magari potrei scrivere un articolo dedicato più avanti. 

Hello, World!

Ho tentato più di una volta in passato di cominciare una specie di blog. Non sono sicuro di aver mai pensato di avere qualcosa di interessante da dire (e di conseguenza non ho mai potuto postare molto), ma piuttosto volevo costruire un sito per il gusto di farlo, cosa che probabilmente è vera anche per questo. Ora però penso di aver raggiunto un punto dove potrei avere qualche contenuto che vale la pena pubblicare.

Hello, World!