Haskell · Cabal · strumenti di build
Le sandbox Cabal: cosa erano e cosa le ha sostituite
cabal sandbox stesso appartiene ormai alla storia — se vuoi solo il workflow moderno, passa direttamente a cosa usare oggi.Quando cabal sandbox arrivò in cabal-install 1.18 nell'agosto 2013, risolse la cosa più fastidiosa dello sviluppo Haskell dell'epoca: il database globale dei pacchetti. Prima delle sandbox, ogni cabal install scriveva in un unico store ~/.cabal condiviso. Installavi due progetti che richiedevano versioni diverse della stessa libreria e ottenevi il famigerato «inferno delle dipendenze» — un database globale corrotto che spesso finiva con rm -rf ~/.ghc ~/.cabal e un nuovo inizio.
Le sandbox resero le dipendenze specifiche per progetto. Quel principio non è mai sparito — ma il meccanismo sì. Ecco il quadro completo, dal funzionamento delle sandbox al workflow in stile nix che le ha sostituite.
Cos'era davvero una sandbox
Una sandbox era un database di pacchetti locale al progetto. Ne creavi uno nella cartella del tuo progetto:
$ cd my-project
$ cabal sandbox init
Writing a default package environment file to
/home/you/my-project/cabal.sandbox.config
Creating a new sandbox at
/home/you/my-project/.cabal-sandbox Da quel momento, cabal install e cabal build eseguiti in quella cartella usavano .cabal-sandbox/ invece dello store globale. Due progetti potevano dipendere da versioni in conflitto di aeson o text senza mai interferire, perché ciascuno aveva il proprio database isolato.
Dipendenze sorgente locali
L'altra funzionalità davvero utile era add-source, che permetteva a una sandbox di includere una libreria direttamente da un repository locale — preziosa quando si armeggia su una libreria e un'applicazione insieme:
$ cabal sandbox add-source ../my-library
$ cabal install --dependencies-only
$ cabal build Modificavi ../my-library, ricostruivi l'applicazione, e cabal rilevava il cambiamento e ricompilava la dipendenza. Era quanto di più vicino a un workflow monorepo Haskell avesse nel 2013.
Perché le sandbox furono infine rimosse
Le sandbox risolvevano l'isolamento ma lasciavano due problemi irrisolti:
- Nessuna condivisione tra progetti. Ogni sandbox ricompilava il mondo da zero. Dieci progetti dipendenti da
lenssignificavano dieci build distinte dilense del suo enorme albero di dipendenze — lento e affamato di disco. - Nessuna riproducibilità tra macchine. Una sandbox catturava dove vivevano i pacchetti, non un piano preciso e riproducibile di quali versioni esatte sarebbero state scelte. Due sviluppatori che eseguivano gli stessi comandi a una settimana di distanza potevano comunque ottenere build diverse.
La soluzione, presa in prestito concettualmente da Nix, fu rendere le build indirizzate per contenuto e condivise globalmente: costruire una data combinazione pacchetto-versione-opzioni una sola volta, memorizzarla sotto un hash in uno store globale immutabile, e lasciare che ogni progetto che necessita di quella combinazione esatta la riutilizzi. Sono le «build locali in stile nix», apparse con il nome new-build in Cabal 2.0.
Cosa usare oggi (2026)
cabal sandbox è stato deprecato durante la serie Cabal 2.x e rimosso del tutto nelle versioni successive. Il moderno workflow predefinito dell'attuale cabal-install non richiede alcun passo di init — l'isolamento è automatico:
# In any project directory with a .cabal file:
$ cabal build # nix-style local build (v2 is the default now)
$ cabal run
$ cabal repl
$ cabal test Ciò che accade sotto il cofano è esattamente l'isolamento per progetto che le sandbox promettevano, più la condivisione che mancava loro:
- Gli artefatti di build del tuo progetto vanno in una cartella locale
dist-newstyle/(il successore spirituale di.cabal-sandbox/). - Le dipendenze compilate vanno in uno store globale immutabile (
~/.cabal/store, oppure sotto~/.local/state/cabalnei layout recenti), indicizzato da un hash di pacchetto, versione, dipendenze e opzioni. Costruiscilensuna volta; ogni progetto che riutilizza lo stesso piano fa riferimento alla stessa voce dello store. - Un file
cabal.projectsostituiscecabal.sandbox.configper la configurazione, le build multi-pacchetto e il pinning.
L'equivalente moderno di add-source
Le dipendenze sorgente locali e remote vivono ora in cabal.project:
# cabal.project
packages: . ../my-library
-- or pull a dependency straight from git:
source-repository-package
type: git
location: https://github.com/owner/some-lib
tag: 0a1b2c3d È nettamente più potente di add-source: gestisce più pacchetti locali, pin git esatti e build multi-repository riproducibili.
Pinning delle versioni riproducibile
Per la riproducibilità che le sandbox non hanno mai offerto, genera un file di freeze che blocca ogni versione transitiva:
$ cabal freeze # writes cabal.project.freeze
# commit it — every machine now resolves the identical plan E Stack in tutto questo?
Stack affronta gli stessi obiettivi da un'altra angolazione: invece di risolvere le versioni per progetto, costruisce contro snapshot curati (i resolver Stackage come lts-22.x) dove un intero insieme di pacchetti è noto compilare insieme, e condivide le build globalmente per snapshot. Entrambi gli strumenti sono solidi e ampiamente usati nel 2026; la suddivisione pratica è grosso modo «voglio la toolchain standard e un controllo fine» (Cabal) contro «voglio un insieme curato e affidabile chiavi in mano» (Stack). Nessuno dei due usa le sandbox — il concetto è pienamente superato da entrambe le parti.
Promemoria di migrazione
cabal sandbox init → (nothing — just `cabal build`)
cabal sandbox add-source ../lib → packages: . ../lib (in cabal.project)
cabal install --dependencies-only → cabal build --only-dependencies
.cabal-sandbox/ → dist-newstyle/ (local) + ~/.cabal/store (shared)
cabal.sandbox.config → cabal.project (+ cabal.project.freeze) La lezione insegnata dalle sandbox — non inquinare mai uno stato mutabile globale, isolare per progetto — ha prevalso così completamente da diventare invisibile: è semplicemente il modo in cui cabal build si comporta. Se stai leggendo questo perché un vecchio link o tutorial ti ha indirizzato a cabal sandbox init, puoi tranquillamente dimenticare quel comando. Esegui semplicemente cabal build.