Currying merupakan metoda yang populer kalangan JavaScript developer untuk membuat function dimana argument-argument dari function tersebut di translate menjadi stand-alone function.
function(a, b) --> function(a)(b)
Di Javascript kita sah-sah saja membuat fungsi begini. Bahkan jadi hal yang umum
function add() {return function(a) {return function(b) {return a + b;}}}
let test = add();
let result = test(2)(3); // a + b -> 2 + 3
console.log(resul); // 5
function diatas itu sama aja seperti function add(a, b) { return a + b }
cuma kita buat "gaya" dikit biar lebih "keriting", agar membentuk format
function(a)(b)
Contoh lain: kita ingin membuat fungsi untuk greeting seseorang dengan format: {greet}, {title}, {name}
function greeting(greet) {return function(title) {return function(name) {return greet + title + name;}}}let greetBudi = greetBudi('Haloo')(' Mr. ')('Budi');console.log(greeting); /* Haloo Mr. Budi *//* bisa juga kita pakai seperti ini */let greet = greeting('Dear, ');let budi = greet('Mr.')('Budi'); /* Dear, Mr.Budi */let agus = greet('Mr.')('Agus'); /* Dear, Mr.Agus */let nina = greet('Mrs.')('Nina'); /* Dear, Mrs.Nina */
Bisa juga di pakai begini...lebih enak untuk Pemisahan objek
let greetCowok = greeting('Hello, ')('Mr. ');let dedi = greetCowok('Dedi'); /* Hello, Mr.Dedi */let ujang= greetCowok('Ujang'); /* Hello, Mr.Ujang */let greetCewek = greeting('Hello, ')('Mrs. ');let siska = greetCewek('Siska'); /* Hello, Mrs.Siska */let lili = greetCewek('Lili'); /* Hello, Mrs.Lili */
Gimana menarik kan? cara diatas lebih flexible dibanding kita pakei function biasa
function greeting_biasa(greet, title, name); {return greet + title + name;}greeting_biasa('Hello ', 'Mr.', 'Agus'); /* Hello Mr.Agus */greeting_biasa('Hello ', 'Mr.', 'Budi'); /* Hello Mr.Budi */greeting_biasa('Hello ', 'Mr.', 'Dedi'); /* Hello Mr.Dedi */
kita perhatikan diatas, kita mesti berulang-ulang panggil greeting_biasa
ditambah paramater nya berulang-ulang juga. jadi kurang flexible dan oleh karena itu currying menjadi opsi yang harus kita coba.
Membuat helper function jadi bener-bener Curry
Curry yang advance biasanya bisa di kawinkan dengan Partial Application.
1. normal call format --> function(a, b, c);
2. curry-partial call format --> function(a)(b, c)
3. fully curry call format --> function(a)(b)(c)
Dan helper curry yang baik itu harus harus bisa memenuhi ke-3 format diatas. Berikut sample code nya
function curry(fn) {return function curried(...args) { /* pakei spread operator */if (args.length >= fn.length) {return fn.apply(this, args);} else {return function(...args2) {return curried.apply(this, args.concat(args2)); /* recursive call */}}}}
Dengan helper baru diatas curry(fn), baru kita bisa tuh pake ke-3 format tadi
Real-world Example. Misal kita ingin membuat fungsi untuk Logging system
function logging(date, type, message) {return date + ':' + '['+type+']' + ' -> ' + message;}
let log = curry(logging);/* normal call */log('today', 'DEBUG', 'Some debug message');/* partial curry call */log('today')('DEBUG', 'Some debug message');/* full curry call */log('today')('DEBUG')('some debug message');let todayLog = log('today');todayLog('DEBUG', 'some debug message');todayLog('DEBUG')('some debug message');let yesterdayLog = log('yesterday');yesterdayLog('DEBUG', 'some debug message');yesterdayLog('DEBUG')('some debug message');let todayDebugLog = log('today', 'DEBUG'); /* bisa juga log('today')('DEBUG') */todayDebugLog('Some debug message');
Memahami Algoritma-nya
Silahkan jalankan kode dibawah ini di browser atau di jsbin.com
function curry(fn) {return function curried(...args) {console.log('args1: ' + args);console.log("length curry vs length original: " + args.length + ':' +fn.length)/*** Jika jumlah argument function yang mau di curry >= original function* langsung aja panggil/apply original function nya*/if (args.length >= fn.length) { /* step #1 */console.log('masuk step #1');return fn.apply(this, args);} else {/*** Jika lebih sedikit, kita proses secara recursif* untuk meng-gabung/merge semua argument* sampai jumlahnya sama dengan original functionnya* dan akhirnya akan kembali masuk ke step #1*/console.log('masuk step #2..');return function(...args2) { /* step #2 */console.log('args2: ' + args2)console.log('final argumen step args1+args2: ' + args.concat(args2));/* gabung argument menjadi [ar1, ar2, ...arn] *//* setelah argument di-merge, kita kembalikan/pass lagi ke function curried() diatas */return curried.apply(this, args.concat(args2));/* recursive call */}}}}function logging(date, type, message) {return date + ':' + '['+type+']' + ' -> ' + message;}let normalLog = curry(logging); // kirim original functionlet res = normalLog('today', 'debug', 'message 1');console.log(res);console.log('-------------------end normal call-------------------------');let res2 = normalLog('today')('debug', 'message 1');console.log(res2);console.log('---------------------end partial call----------------------');let res3 = normalLog('today')('debug')('message 1');console.log(res3);console.log('--------------------end of full-----------------------------');
Silahkan lihat outputnya di Console browser

