Uncategorized
No Comments Haskell
I. Haskell
Haskell merupakan bahasa pemrograman yang fungsional, malas dan murni. Ia disebut ‘malas’ karena tidak mengevaluasi ekspresi-ekspresi yang digunakannya yang sebenarnya memang tidak diperlukan untuk menentukan jawaban bagi suatu masalah. Kebalikan dari ‘malas’ adalah ‘teliti’ yang merupakan strategi pengevaluasian bagi kebanyakan bahasa pemrograman (C, C++, Java, bahkan ML). Salah satu ciri dari bahasa yang teliti adalah setiap ekspresi diteliti apakah hasil dari perhitungan tersebut penting atau tidak.(Hal ini mungkin tidak mutlak benar seluruhnya karena adanya pengoptimalan compiler yang sering disebut dengan“eleminasi kode mati”yang akan menghilangkan ekspresi yang tidak digunakan di program yang sering dilakukan oleh bahasa-bahasa tersebut). Haskell disebut ‘murni’ karena bahasa ini tidak memperbolehkan adanya efek samping (Efek samping adalah sesuatu yang mempengaruhi “bagian” di program. Misalnya suatu fungsi yang mencetak sesuatu ke layar yang mempengaruhi nilai dari variabel global. Tentu saja, suatu bahasa pemrograman yang tanpa efek samping akan menjadi sangat tidak berguna; Haskell menggunakan sebuah system monads untuk mengisolasi semua komputasi kotor dari program dan menampilkannya dengan cara yang aman. Haskell disebut bahasa ‘fungsional’ karena evaluasi dari programnya sama dengan mengevaluasi sebuah fungsi dalam bahasa matematika murni. Hal ini juga yang membedakannya dari bahasa standard (seperti C dan Java) yang mengevaluasi sederetan pernyataan secara urut (inilah pola dari bahasa terstruktur ) Yang termasuk dalam bahasa pemrograman fungsional antara lain Lisp, Scheme, Erlang, Clean, Mercury, ML, OCaml, SQL, XSL dan lain-lain. Di antara bahasa fungsional tersebut, Haskell merupakan bahasa yang ideal dalam banyak hal. Bahasa fungsional seperti juga bahasa logika seperti Prolog adalah deklaratif. Kebalikannya yaitu bahasa procedural dan bahasa yang berorientasi pada obyek adalah terstruktur. Haskell memiliki sintak yang lebih mudah untuk dipahami daripada Lisp–bahasa turunan–(terutama bagi pemrogram yang pernah menggunakan bahasa yang menggunakan tanda baca yang sederhana/ringan seperti Python, TCL and REXX). Kebanyakan operatornya bersifat infix, tapi ada juga yang prefix. Pengaturan indentasi dan modulnya sangatlah familiar dan mungkin sangat menarik, misalnya tanda kurung bersarang yang terlalu dalam (seperti yang terlihat dalam Lisp) dihindari.
II. Sejarah Haskell
Pada bulan September tahun 1987 diadakan pertemuan dalam konferensi Bahasa Pemrograman Fungsional dan Arsitektur Komputer atau Functional Programming Languages and Computer Architecture (FPCA ’87) di Portland, Oregon, untuk membicarakan keadaan yang kurang menguntungkan di komunitas pemrograman fungsional yaitu adanya selusin bahasa pemrograman fungsional yang murni, kesemuanya mirip dalam hal bentuk ekspresi dan sintaknya. Telah dihasilkan suatu konsensus yang kuat dalam pertemuan itu yaitu bahwa penyebarluasan kegunaan dari kelas bahasa fungsional ini telah dihalangi oleh kekurangan dari kebanyakan bahasa. Telah diputuskan juga bahwa harus ada sebuah komite yang dibentuk untuk merancang suatu bahasa yang menyediakan komunikasi gagasan baru yang lebih cepat, suatu dasar yang stabil bagi pengembangan aplikasi nyata dan sebuah cara untuk membuat orang tertarik menggunakan bahasa fungsional. Kemudian diciptakanlah sebuah bahasa pemrograman fungsional yang murni yang dinamai Haskell. Nama tersebut diambil dari nama seorang ahli logika yaitu Haskell B. Curry yang telah menciptakan banyak dasar-dasar logika bagi kita. Tujuan utama dari komite tersebut adalah untuk merancang bahasa yang memenuhi syarat sebagai berikut :
1. Harus cocok untuk pengajaran, penelitian dan aplikasi termasuk untuk membuat sistem yang besar.
2. Harus seluruhnya dijelaskan melalui sintak dan semantik yang formal.
3. Harus tersedia secara bebas. Semua orang boleh mengimplementasikan bahasa tersebut dan menyebarkannya ke siapa saja yang mereka sukai.
4. Harus didasarkan pada gagasan yang sesuai dengan konsensus umum.
5. Harus mengurangi perubahan yang tidak diperlukan dalam bahasa pemrograman fungsional.
Komite tersebut menganggap bahwa Haskell dapat dijadikan sebagai bahan penelitian masa depan dalam bidang rancangan bahasa dan berharap bahwa variasi bahasa akan muncul sesuai dengan hasil percobaan. Haskell kemudian terus berkembang sejak dipublikasikan. Pada pertengahan tahun 1997, telah ada empat rancangan bahasa yang dihasilkan (yang terbaru pada saat itu adalah Haskell 1.4). Pada saat workshop Haskell tahun 1997 di Amsterdam, diputuskan bahwa diperlukan varian yang stabil dari Haskell. Bahasa yang stabil ini disebut “Haskell 98”. Haskell 98 mirip dengan Haskell 1.4, tapi ia menawarkan beberapa penyederhanaan dan penghilangan lubang-lubang jebakan karena ketidakhati-hatian.
III. Kelebihan & Kekurangan Haskell
Kelebihan dari Haskel antara lain:
1. Meningkatkan produktifitas programmer (Ericsson banyak memanfaatkan hasil percobaan Haskell dalam software telephony)
2. Lebih singkat, lebih jelas dan kode-kodenya mudah dibaca
3. Errornya semakin sedikit dan reabilitynya lebih tinggi
4. Membuat jarak antara programmer dengan bahasa itu lebih pendek
5. Waktu untuk membuat program menjadi lebih singkat
Sebagai contoh:
Kelemahan dari Haskell:
1. kode programnya cenderung agak lambat berkembang dibanding program yang sama yang ditulis dalam bahasa seperti C
2. Haskell cenderung sulit untuk didebug.
IV. NILAI, TIPE, DAN ATRIBUT LAINNYA
Tipe Polimorfis
Haskell juga menyertakan tipe polimorfis – tipe yang dalam beberapa cara terukur di atas semua tipe. Ekspresi tipe polimorfis menguraikan keluarga dari tipe-tipe. Sebagai contoh, (
)[a] adalah keluarga dari tipe di mana untuk setiap tipe a berisi tipe list dari a. List dari integer (seperti [1,2,3]), list dari karakter ([‘a’,’b’,’c’]), sekalipun list dari list integer, dll, adalah anggota dari keluarga ini. (Sebagai catatan [2,’b’] bukan contoh yang valid karena tidak ada tipe tunggal yang berisi 2 dan ‘b’).
List merupakan struktur data yang umum digunakan dalam bahasa fungsional, dan merupakan sarana yang baik untuk menerangkan prinsip-prinsip dari polimorfisme. List [1,2,3] dalam Haskell merupakan kependekan dari list 1:(2:(3:[])), di mana [] merupakan list kosong dan : merupakan operator infix yang meletakkan argumen pertama di depan argumen kedua (dalam hal ini list), atau dapat juga ditulis 1:2:3:[].
Sebagai contoh dari fungsi user-defined yang beroperasi pada list, pertimbangkan masalah menghitung jumlah elemen dalam list berikut:
length :: [a] -> Integer
length [] = 0
length (x:xs) = 1 + length xs
Dari persamaan di atas terbaca: “Panjang dari list kosong adalah 0, dan panjang dari list di mana elemen pertamanya x dan sisanya xs adalah 1 ditambah panjang dari xs.” (sebagai catatan xs merupakan jamak dari x, dan harus dibaca demikian).
Walaupun secara intuitif, contoh di atas menyorot sebuah aspek penting dari Haskell, yaitu pattern matching (pencocokan pola). Ruas kiri persamaan mengandung pola seperti [] dan x:xs. Dalam sebuah fungsi aplikasi, pola-pola seperti ini dibandingkan dengan parameter aktual (nyata) dengan cara intuitif ([]x:xs akan cocok dengan list apa saja dengan minimal satu elemen, x dihubungkan dengan elemen pertama dan xs hanya cocok dengan list kosong, dan dengan sisanya dalam list). Jika pencocokan sukses, ruas kanan dievaluasi dan dikembalikan sebagai hasil dari aplikasi. Jika gagal, persamaan berikutnya akan dicoba, dan jika semua persamaan gagal, maka hasilnya error.
Fungsi length di atas juga merupakan contoh dari sebuah fungsi polimorfis. Fungsi tersebut dapat diterapkan pada list yang berisi elemen bertipe apa saja, sebagai contoh [Integer], [Char], atau [[Integer]].
length [1,2,3]
3
length [‘a’,’b’,’c’]
3
length [[1],[2],[3]]
3
Berikut adalah 2 contoh fungsi polimorfis dalam list. fungsi head mengembalikan elemen pertama dari list, fungsi tail mengembalikan semua elemen kecuali elemen pertama.
head :: [a] -> a
head (x:xs) = x
tail :: [a] -> [a]
tail (x:xs) = xs
Tidak seperti fungsi length, fungsi-fungsi di atas tidak didefinisikan untuk semua nilai yang mungkin dari argumen mereka. Runtime error (kesalahan saat program dijalankan) akan muncul saat fungsi-fungsi tersebut diterapkan pada list kosong.
Dengan tipe polimorfis beberapa tipe lebih umum dibanding lainnya dalam hal himpunan nilai yang didefinisikan lebih besar. Sebagai contoh tipe [a][Char]. Dengan kata lain, tipe terakhir dapat diturunkan dari sebelumnya dengan substitusi yang cocok untuk a. Dibandingkan dengan bahasa bertipe monomorfis seperti C, polimorfisme meningkatkan ke-ekspresif-an, dan tipe inferensi meringankan beban tipe dari pemrogram. adalah lebih umum dari
Tipe prinsipal (utama) dari ekspresi atau fungsi adalah tipe yang paling tidak umum, secara intuitif, “berisi semua instan dari ekspresi”. Sebagai contoh, tipe prinsipal dari fungsi head adalah [a] -> a; [b] -> a, a -> a.
Tipe User-Defined
Kita dapat menentukan tipe data sendiri dalam Haskell menggunakan deklarasi data.
Tipe penting yang sudah dikenal oleh Haskell adalah nilai kebenaran:
data Bool = False | True
Tipe yang didefinisikan di sini adalah Bool yang mempunyai dua nilai, yaitu True dan False. Tipe Bool adalah sebuah contoh dari tipe konstruktor, dan True dan False adalah data konstruktor (atau konstruktor saja).
Dengan cara yang sama kita dapat mendefinisikan tipe warna:
data Color = Red | Green | Blue | Indigo | Violet
Bool dan Color dalam contoh di atas merupakan tipe enumerasi.
Berikut contoh dari tipe dengan hanya satu data konstruktor:
data Point a = Pt a a
Karena merupakan konstruktor tunggal, tipe seperti Point sering disebut tipe tuple, karena merupakan produk kartesian (dalam hal ini biner) dari tipe lain. Berlawanan dengan itu, tipe multi-konstruktor seperti Bool dan Colorunion dari tipe sum. disebut
Point merupakan contoh dari tipe polimorfis: untuk semua tipe t, ia mendefinisikan tipe dari titik-titik kartesian yang menggunakan t sebagai tipe koordinat. Dalam contoh sebelumnya [] juga merupakan tipe konstruktor. Pada tipe t (bertipe apa saja) dapat diterapkan [] untuk menghasilkan tipe baru [t]. sintaks Haskell mengizinkan [] t ditulis sebagai [t]. -> juga merupakan tipe konstruktor; diberikan 2 tipe t dan u, t -> u merupakan tipe dari fungsi pemetaan elemen dari tipe t ke elemen dari tipe u.
Catatlah bahwa tipe dari konstruktor data biner Pt adalah a -> a -> Point a, sehingga yang berikut adalah valid:
Pt 2.0 3.0 :: Point Float
Pt ‘a’ ‘b’ :: Point Char
Pt True False :: Point Bool
Pada sisi lain, ekspresi seperti Pt ‘a’ 1 tidak valid karena ‘a’ dan 1 berbeda tipe.
Penting untuk membedakan antara menerapkan data konstruktor untuk menghasilkan nilai, dan menerapkan tipe konstruktor untuk menghasilkan tipe; yang pertama terjadi saat run-time dan bagaimana kita menghitung dalam Haskell, di mana yang terakhir terjadi saat compile-time.
Tipe konstruktor seperti Point dan data konstruktor seperti Pt adalah dalam namespaces terpisah. Ini memungkinkan nama yang sama untuk digunakan oleh tipe konstruktor dan data konstruktor, seperti berikut:
data Point a = Point a a
Tipe Rekursif
Tipe dapat juga rekursif, seperti tipe dalam pohon biner:
data Tree a = Leaf a | Branch (Tree a) (Tree a)
Di sini didefinisikan tipe polimorfis pohon biner yang mana elemen-elemennya adalah node Leaf berisi nilai dari tipe a, atau node internal (“branch”) berisi dua sub-tree (rekursif).
Saat membaca deklarasi data seperti ini, ingat bahwa Tree adalah tipe konstruktor, di mana Branch dan Leaf adalah data konstruktor. Di samping menciptakan koneksi antara konstruktor-konstruktor ini, deklarasi di atas mendefinisikan tipe berikut untuk Branch dan Leaf:
Branch :: Tree a -> Tree a -> Tree a
Leaf :: a -> Tree a
Dengan contoh di atas telah didefinisikan suatu tipe yang cukup kaya untuk mendefinisikan beberapa fungsi (rekursif) yang menggunakannya. Sebagai contoh akan didefinisikan sebuah fungsi fringe yang mengembalikan sebuah list dari semua elemen dalam daun dari sebuah pohon dari kiri ke kanan. Biasanya akan sangat membantu jika dituliskan terlebih dulu tipe dari fungsi baru; dalam kasus ini tipe seharusnya Tree a -> [a]. fringe merupakan fungsi polimorfis di mana untuk semua tipe a, memetakan pohon dari a ke list dari a. Definisi yang tepat sebagai berikut:
fringe :: Tree a -> [a]
fringe (Leaf x) = [x]
fringe (Branch left right) = fringe left ++ fringe right
Di sini ++ merupakan operator infix yang menggabungkan dua list.
Tipe Sinonim
Untuk kenyamanan, Haskell menyediakan cara untuk mendefinisikan tipe sinonim, yaitu nama untuk tipe yang sering dipakai. Tipe sinonim dibuat menggunakan deklarasi type. Berikut beberapa contoh:
type String = [Char]
type Person = (Name,Address)
type Name = String
data Address = None | Addr String
Tipe sinonim tidak mendefinisikan tipe baru, tetapi memberi nama baru kepada tipe-tipe yang sudah ada. Sebagai contoh tipe Person -> Name(String,Address) -> String. Nama yang baru seringkali lebih pendek dari tipe sinonimnya, tetapi itu bukan satu-satunya tujuan dari tipe sinonim: tipe sinonim meningkatkan kemudahan membaca sebuah program dengan menjadi lebih mnemonik. Bahkan tipe polimorfis sekalipun dapat diberi nama baru: setara dengan
type AssocList a b = [(a,b)]
Ini merupakan “tipe asosiasi” yang mengasosiasikan nilai dari tipe a dengan nilai dari tipe b.
Operator
Untuk tipe data angka, terdapat operator aritmatika untuk penjumlahan, pengurangan, perkalian, dan pembagian. Dengan operator-operator tersebut, kita bisa menggunakan interpreter Haskell sebagaimana menggunakan kalkulator. Inilah beberapa contohnya:
? 1 + 1
> 2
? 5 – 3
> 2
? 7 * 7
> 49
? 4 / 2
> 2.0
? (2 * 2) – (4 * 1 * 3)
> -8
? 3.14 * 2.1 * 2.1
> 13.8474
Dalam contoh-contoh di atas, tanda tanya (?) mengawali input yang kita tuliskan dan tanda lebih besar (>) mengawali outputnya. Salah satu hal yang menarik adalah bahwa pembagian Integer dengan Integer menghasilkan bilangan floating point. Hal ini seperti di Pascal, dan berbeda dengan LISP (nenek moyang Haskell) dan C/C++/C#/Java.
Di Haskell, list merupakan tipe data yang fundamental. Seperti yang telah disebutkan, list hanya bisa berisi satu tipe data (misalnya integer). Membuat list sangatlah mudah, yaitu dengan syntax berikut:
? [1, 2, 3, 4]
> [1,2,3,4]
? [‘a’, ‘b’, ‘c’]
> [1,2,3,4]
? [3.14, 2.72]
> [3.14,2.72]
? []
> []
Kita bisa membuat deret aritmatika dengan mudah, misalnya:
? [1..10]
> [1,2,3,4,5,6,7,8,9,10]
? [2,4..20]
> [2,4,6,8,10,12,14,16,18,20]
Kita juga dapat membuat deret tak hingga misalnya [1,3,..], tetapi kalau itu kita lakukan maka interpreter tidak akan pernah selesesai menuliskan anggota deret tersebut (kecuali kalau kita hentikan).
Salah satu operasi list yang sederhana adalah penjumlahan list, contohnya:
? [1..10] ++ [21..30]
Ø [1,2,3,4,5,6,7,8,9,10,21,22,23,24,25,26,27,28,29,30]
V. Kesimpulan
Bahasa pemrograman Haskell merupakan bahasa pemrograman yang sangat sederhana dan mudah dipelajari. Hal ini tidak lain disebabkan karena Haskell merupakan bahasa pemrograman fungsional murni. Oleh karena itu Haskell dapat:
1. Meningkatkan produktifitas programmer (Ericsson banyak memanfaatkan hasil percobaan Haskell dalam software telephony)
2. Lebih singkat, lebih jelas dan kode-kodenya mudah dibaca
3. Errornya semakin sedikit dan reabilitynya lebih tinggi
4. Membuat jarak antara programmer dengan bahasa itu lebih pendek
5. Waktu untuk membuat program menjadi lebih singkat
Selain itu, dalam Haskell tidak ada varibel yang berubah, tidak ada efek samping dari penggunaan sebuah fungsi, tidak ada perulangan, dan tidak ada program order.
Akan tetapi, Haskell sendiri kurang dikenal dibandingkan bahasa-bahasa pemrograman terstruktur. Hal ini disebabkan karena gaya berfikir seorang programmer, terutama programmer yang terbiasa menggunakan bahasa pemrograman terstruktur, harus sedikit diubah ketika ia ingin membuat program dengan menggunakan Haskell. Selain itu, Haskell punya beberapa kelemahan, antara lain:
1. kode programnya cenderung agak lambat berkembang dibanding program yang sama yang ditulis dalam bahasa seperti C
2. Haskell cenderung sulit untuk didebug.


