Pemrograman Deklaratif — Paradigma Fungsional Praktis, Part 1

Bobby Priambodo
Paradigma Fungsional
5 min readJul 20, 2017

Artikel ini adalah bagian dari sebuah seri artikel tentang Paradigma Fungsional Praktis. Silakan lompat ke akhir artikel untuk melihat navigasi keseluruhan seri ini.

Paradigma pemrograman fungsional berarti menjadikan kode Anda deklaratif. Apa maksudnya? Mari cari tahu!

Apa itu Pemrograman Deklaratif?

Dalam hierarki paradigma pemrograman, paradigma pemrograman fungsional merupakan salah satu turunan dari paradigma pemrograman deklaratif. Ketika menjelaskan tentang pemrograman deklaratif, umumnya ada satu kalimat yang sering diucapkan:

Pemrograman deklaratif lebih fokus pada apa (what) dibanding bagaimana (how).

Kalau Anda tidak langsung mengerti, tidak apa-apa. Saya juga demikian. Mari lihat apa kita bisa memperbaiki ini.

Untuk mempermudah, ada baiknya kita mengetahui kontras dari paradigma deklaratif, yaitu paradigma imperatif. Sesuai namanya, paradigma imperatif adalah pendekatan pemrograman memberitahu komputer bagaimana cara melakukan sesuatu. Berikut adalah contoh pemrograman imperatif di Javascript.

let numbers = [4, 15, 20, 9, 11, 18];let evenNumbers = [];
for (let i = 0; i < numbers.length; i++) {
let currentNumber = numbers[i];
if (currentNumber % 2 == 0) {
evenNumbers.push(currentNumber);
}
}
// Sekarang evenNumbers berisi [4, 20, 18]

Hampir semua programmer yang datang dari dunia Java, C, dan C++, pasti pernah menulis kode seperti ini. Kalau kita membaca kodenya baik-baik, kita bisa tahu bahwa tujuan potongan kode tersebut adalah mengambil bilangan-bilangan genap dari array numbers, tapi itu tidak terlalu jelas jika hanya dilihat sekilas. Terlalu banyak detail yang tidak penting. Sekarang, mari kita lihat pendekatan deklaratifnya.

let numbers = [4, 15, 20, 9, 11, 18];let evenNumbers = filter(numbers, el => el % 2 == 0);// Sekarang evenNumbers berisi [4, 20, 18]

Logika yang sama, bahasa yang sama, namun kali ini lebih ringkas.

Tapi tunggu!” saya dengar Anda berseru. “Itu curang! Dari mana datangnya fungsi filter?” Itu poin yang bagus. Mari kita lihat definisi fungsi filter.

/**
* Filters elements of a list based on predicate fn.
*/
function filter(list, fn) {
let result = [];
for (let i = 0; i < list.length; i++) {
let currentEl = list[i];
if (fn(currentEl)) {
result.push(currentEl);
}
}
return result;
}

Anda benar, itu sama saja dengan yang telah kita lakukan pendekatan imperatif di awal. Jadi apa manfaatnya? Mari lihat kembali satu baris dari pendekatan deklaratif kita:

let evenNumbers = filter(numbers, el => el % 2 == 0)

Baris ini mengandung esensi dari pemrograman deklaratif: mendeskripsikan suatu hal tanpa peduli bagaimana cara mendapatkannya. Ini adalah jawaban untuk pengertian apa dan bagaimana yang ada di awal bagian ini. Pemanggil fungsi hanya butuh tahu apa yang ia butuhkan. Bagaimana filter bekerja adalah detail implementasi yang tidak perlu kita ketahui.

Baris tersebut bahkan bisa dibaca dengan baik: kita bisa mengerti bahwa evenNumbers adalah hasil filter (menyaring) dari elemen-elemen pada numbers yang habis dibagi dua.

Bandingkan dengan membaca: evenNumbers merupakan array kosong. Lalu, set variabel i sebagai 0, dan pastikan bahwa i lebih kecil dari ukuran array sekarang, lalu… Terlalu banyak hal tidak relevan yang harus diperhatikan pada pendekatan imperatif kita. Itu berarti semakin banyak pula kode yang berpotensi menimbulkan bug.

Tapi Anda masih benar, hal-hal tersebut masih ada pada implementasi fungsi filter yang kita buat. Berita baiknya, seringkali Anda tidak perlu menulis fungsi filter Anda sendiri. Banyak bahasa pemrograman yang sudah memiliki fungsi serupa pada standard library-nya. Beberapa contoh:

// Javascript ES6
let evenNumbers = numbers.filter(el => el % 2 == 0)
// Python
even_numbers = filter(lambda el: el % 2 == 0, numbers)
// Ruby
even_numbers = numbers.select {|el| el % 2 == 0}
// Java 8
List<Integer> evenNumbers = numbers.stream()
.filter(x -> x % 2 == 0)
.collect(Collectors.toList());
// C#
List<int> evenNumbers = numbers.FindAll(x => x % 2 == 0);
// Haskell
evenNumbers = filter (\el -> el `mod` 2 == 0) numbers
// OCaml
let even_numbers = List.filter ~f:(fun el -> el % 2 = 0) numbers
// Elixir
even_numbers = Enum.filter numbers, fn el -> rem(el, 2) == 0 end

(Note: Selain filter, ada banyak fungsi lain yang beroperasi pada collection, seperti misalnya map atau reduce/fold. Jika Anda mengetahui hal-hal tersebut, besar kemungkinan Anda tak akan lagi menulis for loop!)

Sebuah abstraksi untuk maksud Anda

Pada akhirnya, paradigma pemrograman deklaratif adalah tentang abstraksi. Abstraksi satu level lebih tinggi yang memungkinkan Anda mendeskripsikan intent — maksud dari kode Anda. Hal ini memiliki manfaat agar kode yang Anda tulis dapat dengan mudah dimengerti oleh kolega Anda, dan yang paling penting: oleh Anda sendiri di masa depan.

Pada bahasa pemrograman yang disebut “fungsional”, hal ini seringkali lebih mudah dibanding bahasa lainnya, karena ada banyak fungsi-fungsi di standard library yang sudah menyembunyikan detail low-level-nya dari kita sehingga kita dapat lebih fokus pada logika bisnis aplikasinya. Namun Anda dapat mengimplementasikan pola pikir deklaratif dalam bahasa apa pun. Intinya adalah pastikan client dari class/module/function yang Anda buat tidak perlu tahu detail implementasi dari kode Anda. Client cukup tahu apa yang akan kode Anda berikan.

Umumnya menulis kode secara deklaratif berarti Anda harus banyak mempelajari kapabilitas seperti language construct dan library yang ada pada platform yang Anda gunakan. Hal ini mungkin membuat Anda lebih lama untuk membangun sesuatu, namun pembelajaran itu bisa dilakukan sambil jalan, tidak perlu sekaligus dalam satu kesempatan. Semakin Anda kenal lebih banyak fungsi, semakin mungkin Anda menulis kode yang ekspresif dan mudah dimengerti.

Jadi itu adalah karakteristik pertama dari paradigma fungsional: abstraksi detail implementasi sejauh mungkin. Pelajari dan gunakan standard library atau third party library jika memungkinkan. Buat kode Anda deklaratif.

Pada artikel selanjutnya, kita akan membahas karakteristik berikutnya dari paradigma fungsional, yaitu tentang pure functions dan side effects — fungsi murni dan efek samping. Klik tautan berikut untuk ke artikel selanjutnya:

Atau gunakan navigasi di bawah ini untuk melihat artikel lainnya:

  1. Perkenalan Paradigma Pemrograman Fungsional Praktis
  2. Pemrograman Deklaratif — Paradigma Fungsional Praktis, Part 1
  3. Pure Functions dan Efek Samping — Paradigma Fungsional Praktis, Part 2
  4. Transformasi Data dan Immutability — Paradigma Fungsional Praktis, Part 3
  5. Higher-order Function — Paradigma Fungsional Praktis, Part 4
  6. Penerapan Paradigma Fungsional di Industri — Paradigma Fungsional Praktis, Part 5

Apakah Anda menyukai yang Anda baca? Apa saya melewatkan sesuatu? Beritahu saya melalui kolom komentar!

Paradigma Fungsional adalah sebuah blog tentang berbagai hal yang berkaitan dengan paradigma pemrograman fungsional (functional programming) di dunia pengembangan software. Tulisan-tulisan di blog ini akan dimuat dalam Bahasa Indonesia, karena menurut saya resource untuk belajar paradigma fungsional dalam bahasa kita masih sangat kurang.

Apabila Anda tertarik untuk mengetahui lebih lanjut tentang dunia paradigma fungsional, silakan ikuti blog ini!

--

--

Bobby Priambodo
Paradigma Fungsional

Software Engineer. Functional programming and distributed systems enthusiast. Java, JavaScript, Elixir, OCaml, Haskell.