GHCi adalah lingkungan interaktif yang disertakan bersama GHC untuk mengevaluasi ekspresi Haskell tanpa harus menulis program utuh. Topik ini membahas cara kerja lingkungan tersebut, evaluasi ekspresi, penelusuran tipe dengan perintah :t, pemuatan berkas definisi, dan perintah-perintah dasar yang sering digunakan. Setelah mengikuti topik ini, GHCi dapat digunakan sebagai arena untuk mencoba gagasan sebelum gagasan itu dituliskan menjadi program.
Lingkungan interaktif GHCi#
GHCi menerapkan pola REPL (read-eval-print loop), yaitu siklus yang membaca satu ekspresi, mengevaluasinya, mencetak hasilnya, lalu menunggu ekspresi berikutnya. Lingkungan ini dimulai dengan perintah ghci pada terminal, dan prompt yang tampil menunjukkan nama modul yang sedang dimuat, misalnya Prelude>. Keluar dari lingkungan dilakukan melalui perintah :quit atau pintasan :q. Walaupun berperan seperti penerjemah, GHCi tidak menafsirkan ekspresi baris demi baris secara naif, melainkan mengompilasi setiap ekspresi menjadi bytecode sebelum mengevaluasinya, sehingga jawaban muncul dengan cepat.
Hasil evaluasi pada sesi interaktif tersimpan dalam nama it, sehingga hasil sebelumnya dapat dirujuk pada ekspresi berikutnya. Karena seluruh fungsi Haskell murni, evaluasi ekspresi di GHCi tidak mengubah keadaan apa pun dan mencoba ulang ekspresi yang sama selalu menghasilkan keluaran yang sama. Sifat ini menjadikan GHCi tempat yang aman untuk eksperimen karena tidak ada berkas maupun keadaan lain yang berubah akibat evaluasi.
Evaluasi ekspresi#
Ekspresi apa pun yang menghasilkan nilai dapat dievaluasi, mulai dari aritmetika, panggilan fungsi pustaka standar, sampai kombinasi keduanya. Opsi -e menerima satu ekspresi dalam tanda kutip, mengevaluasinya, lalu mencetak hasilnya ke terminal. Contoh berikut memuat tiga evaluasi yang berjalan langsung dari terminal.
# evaluasi ekspresi aritmetika
ghci -e '2 ^ 10'
# terapkan fungsi pengali dua ke setiap elemen list
ghci -e 'map (* 2) [1 .. 5]'
# potong teks menjadi list kata
ghci -e 'words "haskell adalah bahasa fungsional"'1024
[2,4,6,8,10]
["haskell","adalah","bahasa","fungsional"]Baris pertama menggunakan operator pangkat ^ untuk menghitung dua pangkat sepuluh, yaitu 1024. Baris kedua menerapkan ekspresi (* 2), yaitu fungsi yang mengalikan masukannya dengan dua, pada setiap elemen list [1 .. 5]. Baris ketiga memanggil words, yaitu fungsi pustaka standar yang memotong teks bertipe String menjadi list kata. Hasil yang bertipe list dicetak dalam tanda kurung siku dengan pemisah koma, sedangkan String dicetak dengan tanda kutip. Apabila hasil sebuah ekspresi tidak dapat dicetak, misalnya fungsi yang belum menerima seluruh argumennya, GHCi menampilkan pesan error yang menyebut ketiadaan instans Show untuk hasil tersebut.
Penelusuran tipe dengan :t#
Perintah :t, singkatan dari :type, menampilkan tipe sebuah ekspresi tanpa mengevaluasinya. Perintah ini menjadi alat utama untuk membaca pustaka standar karena tipe yang tampil menjelaskan apa yang diterima dan dikembalikan sebuah fungsi sebelum kodenya dicoba. Kebiasaan menelusuri tipe lebih dahulu juga membantu menemukan argumen yang belum diberikan.
# telusuri tipe bilangan literal
ghci -e ':t 42'
# telusuri tipe fungsi map dari pustaka standar
ghci -e ':t map'
# telusuri tipe operator penggabung list
ghci -e ':t (++)'42 :: Num a => a
map :: (a -> b) -> [a] -> [b]
(++) :: [a] -> [a] -> [a]Tanda :: memisahkan ekspresi dari tipenya, sedangkan huruf kecil seperti a dan b adalah variabel tipe (type variable), yaitu tempat yang dapat diisi tipe apa pun. Baris map :: (a -> b) -> [a] -> [b] dibaca dari kiri ke kanan: map menerima fungsi dari a ke b, kemudian list berisi a, dan menghasilkan list berisi b. Baris 42 :: Num a => a memuat tanda => yang menyatakan batasan (constraint), yakni 42 cocok untuk sebarang tipe yang mendukung operasi aritmetika yang didefinisikan oleh type class Num, bukan berarti 42 tanpa tipe. Terakhir, operator (++) ditulis dalam tanda kurung agar dapat dirujuk sebagai nilai, dan tipenya menunjukkan bahwa kedua list yang digabung harus bertipe sama.
Memuat definisi dari berkas#
Definisi yang ditulis sendiri dapat dicoba dengan pola yang sama. Berkas berikut memuat dua fungsi kecil yang menjadi bahan eksperimen sepanjang topik ini. Bagian main di akhir berkas menjadikannya program utuh, sehingga keluarannya dapat direproduksi melalui runghc.
-- Definisi kecil untuk dicoba di GHCi
kaliDua :: Int -> Int
kaliDua x = x * 2
bertambah :: Int -> Int
bertambah x = x + 1
main :: IO ()
main = do
print (kaliDua 21)
print (bertambah 20)
print (kaliDua (bertambah 20))42
21
42Pada sesi interaktif, berkas dimuat melalui ghci kali-dua.hs atau perintah :load, sehingga fungsi di dalamnya dapat langsung dipanggil pada prompt. Opsi berkas pada ghci -e meniru pemuatan tersebut dalam satu perintah, seperti pada contoh berikut. Ketiga perintah menggunakan berkas yang sama, sehingga hasilnya mudah dibandingkan berdampingan.
# evaluasi fungsi dari berkas yang dimuat
ghci -e 'kaliDua 21' kali-dua.hs
# gabungkan dua fungsi dalam satu ekspresi
ghci -e 'kaliDua (bertambah 20)' kali-dua.hs
# telusuri tipe fungsi yang dimuat
ghci -e ':t kaliDua' kali-dua.hs42
42
kaliDua :: Int -> IntEkspresi ketiga menunjukkan bahwa :t juga berlaku untuk definisi buatan sendiri, sehingga tipe sebuah fungsi dapat diverifikasi tanpa membuka berkasnya. Apabila berkas disunting saat sesi interaktif masih berjalan, versi lama tetap termuat sampai perintah :r dijalankan. Dengan demikian, perubahan hanya berlaku setelah pemuatan ulang dan tidak berlaku secara diam-diam.
Perintah-perintah dasar#
Tabel berikut merangkum perintah GHCi yang paling sering digunakan sehari-hari. Semua perintah diawali tanda titik dua, dan beberapa di antaranya memiliki bentuk panjang yang setara. Bentuk pendek itulah yang lazim diketik, sedangkan bentuk panjangnya dicantumkan pada kolom kedua sebagai rujukan.
| Perintah | Fungsi |
|---|---|
:t ekspresi | menampilkan tipe ekspresi, singkatan :type |
:i nama | menampilkan informasi lengkap sebuah nama, termasuk instans type class-nya, singkatan :info |
:k Tipe | menampilkan kind sebuah tipe, singkatan :kind |
:l berkas | memuat berkas sumber ke sesi yang berjalan, singkatan :load |
:r | memuat ulang berkas yang telah termuat, singkatan :reload |
:browse Modul | menampilkan seluruh nama yang diekspor sebuah modul beserta tipenya |
:q | keluar dari GHCi, singkatan :quit |
Dua perintah pada tabel yang belum dipraktikkan adalah :k dan :browse. Perintah :k menampilkan kind, yaitu tipe bagi tipe, sedangkan :browse menampilkan isi sebuah modul. Contoh berikut mempraktikkan keduanya.
# telusuri kind dari tipe Maybe
ghci -e ':k Maybe'
# telusuri isi modul Data.Bool
ghci -e ':browse Data.Bool'Maybe :: * -> *
Data.Bool.bool :: a -> a -> Bool -> a
(&&) :: Bool -> Bool -> Bool
type Bool :: *
data Bool = False | True
not :: Bool -> Bool
otherwise :: Bool
(||) :: Bool -> Bool -> BoolKeluaran pertama berarti Maybe membutuhkan satu tipe untuk menjadi tipe lengkap, sehingga Maybe Int sah sedangkan Maybe sendiri belum menjadi tipe lengkap. Keluaran kedua memuat tipe data Bool, konstruktornya False dan True, serta fungsi-fungsi modul tersebut beserta tipenya. Nama Data.Bool.bool tampil berawalan modul karena Prelude juga mengekspor fungsi bernama bool, sehingga keduanya perlu dibedakan.
Kesalahan umum#
Kesalahan paling lazim saat bereksperimen di GHCi berupa pemanggilan fungsi sebelum berkasnya dimuat. Kesalahan serupa muncul pula pada sesi interaktif apabila :load belum dijalankan. Contoh berikut memanggil kaliDua tanpa menyertakan berkas yang mendefinisikannya.
# memanggil fungsi sebelum berkasnya dimuat
ghci -e 'kaliDua 21'<interactive>:0:1: error: [GHC-88464]
Variable not in scope: kaliDua :: t0 -> tPesan Variable not in scope berarti nama tersebut tidak dikenal pada lingkup saat perintah dijalankan. Keluaran seperti ini bukan tanda kerusakan pemasangan, melainkan petunjuk arah yang menyebut nama yang belum dikenal beserta tipenya. Perbaikannya dengan menyertakan nama berkas pada perintah atau memuat berkasnya melalui :load terlebih dahulu, sebagaimana contoh pada bagian Memuat definisi dari berkas.
Kesalahan kedua yang lazim berupa perilaku lama yang masih muncul setelah berkas disunting. Sesi interaktif tidak membaca ulang berkas secara otomatis, sehingga perintah :r perlu dijalankan setelah setiap penyuntingan sebelum hasil baru dapat dicoba. Kesalahan ini tidak menimbulkan pesan apa pun, sehingga penyuntingan yang belum dimuat ulang mudah terlewat.
Ringkasan#
- GHCi adalah REPL yang membaca ekspresi, mengevaluasinya, dan mencetak hasilnya, dengan
ghci -e 'ekspresi'sebagai mode satu evaluasi. - Perintah
:tmenampilkan tipe ekspresi dan menjadi cara utama membaca tipe fungsi pustaka standar sebelum digunakan. - Definisi buatan sendiri dimuat melalui nama berkas atau
:load, lalu fungsi di dalamnya dapat dipanggil dan ditelusuri tipenya. - Perintah
:k,:browse,:r, dan:imelengkapi pekerjaan harian, dari kind hingga pemuatan ulang berkas.
Referensi#
- Using GHCi — Glasgow Haskell Compiler User’s Guide — Bab resmi dokumentasi GHC tentang perintah, opsi, dan perilaku GHCi.
- Documentation — haskell.org — Halaman dokumentasi resmi Haskell yang merangkum tutorial dan referensi bahasa.
- base package — Hackage — Dokumentasi pustaka standar yang berisi fungsi dan tipe yang dicoba pada topik ini.