Mengelola proyek Haskell secara profesional dengan cabal: struktur cabal.project dan file .cabal berisi exposed-modules, dependencies dan GHC options, alur build test run, snapshot reproducible dengan stack dan resolver Stackage LTS, serta setup HLS yang konsisten dengan versi GHC.

Sampai episode 8 kalian menjalankan kode dengan runghc dan GHCi. Di episode 9 ini kita naik level: mengelola proyek Haskell yang sebenarnya — dengan dependensi, banyak modul, dan build yang reproducible. Ini adalah titik di mana kode "lab" berubah menjadi kode "produksi".
Mengapa bab ini penting? Karena hampir semua proyek Haskell di dunia nyata dibangun dengan cabal atau stack. Memahami file .cabal, cabal.project, dan snapshot stack berarti kalian bisa berkontribusi ke proyek open source, membangun aplikasi dengan dependensi puluhan paket, dan mengatasi error build yang selama ini terasa seperti kotak hitam.
Proyek cabal terdiri dari dua file kunci: cabal.project (konfigurasi level proyek) dan file *.cabal (deskripsi paket).
Ini adalah "peta" sebuah paket. Contoh minimal:
cabal-version: 3.0
name: hello-lab
version: 0.1.0.0
executable hello-lab
main-is: Main.hs
build-depends: base >= 4.17 && < 5
hs-source-dirs: app
default-language: Haskell2010Bagian-bagian pentingnya:
executable hello-lab mendefinisikan binary bernama hello-lab.main-is: Main.hs menunjuk file dengan fungsi main.build-depends: base >= 4.17 mendeklarasikan dependensi — di sini base (yang berisi Prelude). Operator && menghubungkan batas bawah dan atas.hs-source-dirs: app lokasi file sumber.Untuk paket yang lebih besar, definisikan komponen library yang mengekspos modul agar bisa di-import oleh executable dan test:
library
exposed-modules: MathOps
build-depends: base >= 4.17 && < 5
hs-source-dirs: src
executable hello-lab
main-is: Main.hs
build-depends: base, hello-lab
hs-source-dirs: app
default-language: Haskell2010exposed-modules adalah daftar modul yang bisa di-import pihak lain. Perhatikan build-depends: base, hello-lab di executable — executable memakai library dari paket yang sama. Struktur inilah yang dipakai oleh hampir semua proyek Haskell modern: kode di src/, executable tipis di app/, test di test/.
cabal.project berada di akar proyek dan mengatur konfigurasi level paket — memilih paket yang ikut dibangun, opsi GHC global, dan sumber tambahan:
packages: .
tests: True
optimization: 2
package *
ghc-options: -Wall -Werrorpackages: . berarti "bangun paket di direktori ini", tests: True mengaktifkan komponen test, dan blok package * menerapkan ghc-options ke semua paket. -Wall -Werror menjadikan semua peringatan sebagai error — praktik ketat yang akan kita bahas di episode 17.
cabal build # kompilasi semua komponen
cabal test # jalankan test suite
cabal run hello-lab # jalankan executable tertentu
cabal repl # GHCi dengan konteks paket
cabal list --installed # lihat paket terinstallcabal repl sangat berguna: membuka GHCi dengan semua dependensi paket kalian ter-load, jadi bisa mencoba fungsi dari src/ langsung.
stack membungkus cabal dan menambahkan snapshot: kumpulan versi paket yang sudah diuji kompatibel (dari Stackage). Daripada kalian menentukan versi tiap dependensi, stack menentukan satu resolver LTS dan menurunkannya untuk semua paket.
resolver: lts-23.5
packages:
- .resolver: lts-23.5 memilih snapshot LTS tertentu. Selama resolver tetap sama, setiap developer dan CI akan menginstall versi persis yang sama — inilah reproduktifitas. Perintahnya nyaris identik dengan cabal:
stack build
stack test
stack run hello-lab
stack ghci| Kebutuhan | Pilihan |
|---|---|
| Kontrol penuh versi dependensi | cabal |
| Reproduktifitas tinggi untuk tim/CI | stack (resolver tetap) |
| Menulis library untuk Hackage | cabal |
| Belajar cepat tanpa mikir versi | stack |
| Proyek lama yang sudah pakai salah satu | ikuti yang ada |
Keduanya berbagi format file .cabal — jadi pindah dari stack ke cabal (atau sebaliknya) tidak mengharuskan menulis ulang deskripsi paket.
Tip
Tips praktis: jika proyek sudah punya stack.yaml, gunakan stack; jika hanya cabal.project, gunakan cabal. Menjalankan keduanya di proyek yang sama jarang menjadi masalah (file .cabal sama), tetapi jangan sampai memakai dua lockfile yang saling menimpa build cache — pilih satu sebagai primary.
Haskell Language Server butuh versi GHC yang sama dengan proyek kalian. Langkah standar:
ghcup set ghc 9.14.1
ghcup install hls recommended
ghcup set hls recommendedJika proyek memakai GHC berbeda (lewat stack.yaml), stack mengelola HLS-nya sendiri dengan stack install hls dan stack --version otomatis. Verifikasi di VS Code: buka file .hs, pastikan tipe muncul saat hover dan tidak ada pesan "HLS not found".
Perbedaan penting: cabal repl dan stack ghci memuat konteks proyek — dependensi dan modul kalian siap pakai. GHCi biasa hanya tahu Prelude. Selama development, selalu gunakan versi yang sesuai toolchain proyek kalian.
Warning
Error build "cannot satisfy -package-id" atau "unexpected GHC version" hampir selalu karena dua GHC berbeda dipakai oleh toolchain dan HLS. Periksa dengan ghc --version dan ghcup list; pastikan versi yang aktif (tagged) sesuai dengan yang dipakai proyek.
.cabal dan cabal.project di direktori salah — .cabal berada di folder paket, cabal.project di akar proyek.exposed-modules — import MyModule gagal walaupun file-nya ada.base terlalu ketat — base >= 4.17 && < 4.18 akan pecah saat GHC di-upgrade. Gunakan < 5 sebagai batas atas agar masa pakai lebih lama.-Wall tidak diaktifkan — di episode 17 kalian akan lihat betapa banyak bug yang dicegah hanya oleh warning ini.Inti yang harus dibawa pulang:
*.cabal (deskripsi paket) + cabal.project (konfigurasi level proyek).exposed-modules mendaftarkan API library; build-depends mendeklarasikan dependensi.cabal build, cabal test, cabal run, cabal repl.ghcup set untuk menyamakannya.Di episode 10 selanjutnya kita akan membahas testing (HUnit/Hspec/QuickCheck) & debug — menulis unit test dengan HUnit dan spesifikasi BDD dengan Hspec, property-based testing dengan QuickCheck, menghitung coverage dengan hpc, serta debugging dengan :t/:i, Debug.Trace, dan :set +s. Sampai jumpa di episode 10!