Aksi dasar IO menyediakan interaksi yang paling umum antara program dan dunia luar, yaitu mencetak teks ke terminal, membaca satu baris masukan, serta menulis dan membaca berkas. Topik ini membahas putStrLn, print, getLine, writeFile, dan readFile beserta tipenya. Setelah membacanya, program utuh yang berinteraksi dengan pengguna melalui terminal dan menyimpan datanya dalam berkas dapat ditulis dan dijalankan.
Menampilkan teks dengan putStrLn dan print#
putStrLn :: String -> IO () mencetak satu String ke terminal lalu menambahkan baris baru, sedangkan print :: Show a => a -> IO () mencetak nilai dari tipe apa pun yang dapat diubah menjadi teks melalui fungsi show. Perbedaannya paling terlihat pada String, karena show membungkusnya dengan tanda kutip, sedangkan putStrLn mencetaknya apa adanya. Program berikut menampilkan kedua perilaku tersebut berdampingan.
main :: IO ()
main = do
putStrLn "Suhu pagi: 24"
putStrLn "Suhu siang: 31"
print "Suhu malam: 26"
print (24 + 31)Suhu pagi: 24
Suhu siang: 31
"Suhu malam: 26"
55Baris ketiga keluaran memuat tanda kutip karena "Suhu malam: 26" dicetak melalui print, sehingga show ikut mengutip teksnya. Baris keempat menunjukkan kegunaan utama print, yaitu menampilkan angka dan nilai bertipe lain tanpa menyusun String secara manual. Pada pekerjaan sehari-hari, putStrLn dipilih untuk teks yang telah tersusun, sedangkan print dipilih untuk nilai yang hanya perlu diperlihatkan.
Membaca satu baris dengan getLine#
getLine :: IO String membaca satu baris dari masukan standar sampai tombol Enter ditekan, kemudian menyampaikan baris tersebut tanpa karakter baris baru di ujungnya. Aksi ini tidak menerima argumen, sehingga hasilnya diikat dengan panah <- sebelum dapat digunakan. Program berikut bertanya nama pengguna lalu menyapanya.
-- tidak-dijalankan
main :: IO ()
main = do
putStrLn "Siapa namanya?"
nama <- getLine
putStrLn ("Halo, " ++ nama ++ "!")Program ini menunggu masukan dari papan ketik ketika dijalankan secara langsung, sehingga demonstrasinya disalurkan melalui pipa (pipe), yaitu mekanisme shell yang mengirim keluaran satu perintah menjadi masukan perintah lain. Baris echo "Ali" mengirim teks Ali kepada program melalui masukan standarnya.
# jalankan program sapaan dengan masukan lewat pipa
echo "Ali" | runghc sapa.hsSiapa namanya?
Halo, Ali!Baris pertama keluaran berasal dari putStrLn, sedangkan baris kedua menyusul setelah getLine selesai membaca. Pola tanya lalu jawab seperti ini menjadi dasar program teks interaktif. Apabila masukan berakhir sebelum satu baris lengkap terbaca, getLine melempar exception, sebagaimana ditunjukkan pada bagian Kesalahan umum.
Menulis berkas dengan writeFile#
writeFile :: FilePath -> String -> IO () menulis seluruh isi String ke berkas pada FilePath, yaitu tipe sinonim untuk String yang menandai alamat berkas. Apabila berkas tujuan sudah ada, isinya ditimpa seluruhnya tanpa peringatan, sedangkan berkas baru dibuat apabila belum ada. Program berikut menyimpan satu catatan singkat.
main :: IO ()
main = do
writeFile "catatan.txt" "haskell menyimpan efek dalam tipe IO\n"
putStrLn "Catatan tersimpan"Catatan tersimpanPerintah cat pada terminal memperlihatkan isi berkas yang baru ditulis, dan hasilnya persis teks yang ditulis program, termasuk karakter baris baru di ujungnya.
# tampilkan isi berkas yang baru ditulis program
cat catatan.txthaskell menyimpan efek dalam tipe IOBerkas catatan.txt berada di direktori kerja tempat program dijalankan, karena writeFile menerima alamat relatif terhadap direktori tersebut. Pola program yang menulis berkas lalu memperlihatkan isinya digunakan pula pada demonstrasi berikutnya, sehingga keluaran dapat direproduksi tanpa berkas awal apa pun.
Membaca berkas dengan readFile#
readFile :: FilePath -> IO String membaca seluruh isi berkas dan menyampaikannya sebagai String, sehingga isi berkas dapat diolah dengan fungsi list biasa seolah-olah berasal dari literal. Program berikut menulis berkas terlebih dahulu, membacanya kembali, lalu menghitung jumlah kata dan barisnya.
main :: IO ()
main = do
writeFile "artikel.txt" "haskell menyimpan efek dalam tipe IO\nbaca berkas lalu hitung katanya\n"
teks <- readFile "artikel.txt"
putStrLn ("Jumlah kata: " ++ show (length (words teks)))
putStrLn ("Jumlah baris: " ++ show (length (lines teks)))Jumlah kata: 11
Jumlah baris: 2Fungsi words memotong teks menjadi list kata dan lines memotongnya menjadi list baris, sehingga penghitungan tinggal memanggil length. Berkas artikel.txt ditulis oleh program yang sama pada awal main, sehingga demonstrasi ini berdiri sendiri di direktori mana pun dan keluarannya tetap sama pada setiap eksekusi. Apabila berkas yang diminta tidak ada, readFile berhenti dengan pesan error yang menyebut nama berkasnya, sebagaimana ditunjukkan pada bagian berikut.
Kesalahan umum#
Kesalahan yang paling lazim berupa membaca berkas yang tidak ada. readFile berhenti dengan exception yang menyebut nama berkas beserta penyebabnya, dan pesan tersebut dapat direproduksi dengan mengevaluasi aksinya melalui GHCi.
# membaca berkas yang tidak pernah dibuat
ghci -e 'readFile "tidak-ada.txt"'<interactive>: tidak-ada.txt: openFile: does not exist (No such file or directory)Pesan does not exist berarti berkas dengan nama tersebut tidak ditemukan pada direktori kerja saat program dijalankan. Perbaikannya berupa memeriksa ejaan nama berkas, memastikan program dijalankan dari direktori yang benar, atau membuat berkasnya terlebih dahulu sebelum dibaca.
Kesalahan kedua berupa kebingungan antara putStrLn dan print pada teks, yang membuat tanda kutip tiba-tiba muncul pada keluaran. putStrLn mencetak teks apa adanya, sedangkan print menampilkan nilai melalui show termasuk tanda kutip untuk String. Apabila keluaran program memuat tanda kutip yang tidak diinginkan, periksa aksi mana yang digunakan pada baris tersebut sebelum mengubah datanya.
Ringkasan#
putStrLnmencetakStringapa adanya diikuti baris baru, sedangkanprintmenampilkan nilai melaluishowtermasuk tanda kutip untukString.getLinemembaca satu baris masukan standar tanpa karakter baris baru, dan hasilnya diikat dengan<-sebelum digunakan.writeFilemenimpa berkas tujuan dengan isi baru tanpa peringatan, sedangkanreadFilemenyampaikan seluruh isi berkas sebagaiString.- Program contoh membuat berkas yang akan dibacanya sendiri, sehingga keluarannya tetap sama pada setiap eksekusi.
Referensi#
- System.IO — Hackage
— Dokumentasi resmi modul yang memuat
putStrLn,getLine,readFile, danwriteFile. - 7 Basic Input/Output — Haskell 2010 Language Report — Spesifikasi primitif masukan keluaran yang menjadi dasar aksi-aksi pada topik ini.
- runghc — Glasgow Haskell Compiler User’s Guide — Panduan resmi pelari program yang digunakan untuk mengeksekusi contoh.