Operator pipeline

Operator |> dan >> untuk merantai transformasi menjadi aliran data yang terbaca dari atas ke bawah.

Daftar isi

Operator pipeline menyusun transformasi data menjadi rangkaian langkah yang dibaca dari atas ke bawah, dan topik ini membahas operator |> serta >> sebagai pasangan utamanya. Pembahasan dimulai dari makna |>, dilanjutkan dengan perbandingan kode bersarang dan versi pipeline pada pengolahan nilai ujian, lalu ditutup dengan pipeline bernama yang merupakan hasil komposisi. Setelah topik ini dibaca, rantai transformasi dapat ditulis tanpa tanda kurung bersarang dan tetap terbaca mengikuti urutan pengerjaannya.

Operator |> meneruskan nilai#

Operator |> meneruskan nilai pada ruas kirinya ke fungsi pada ruas kanannya, sehingga x |> f bernilai sama dengan f x. Perbedaannya murni pada urutan penulisan, yaitu data dituliskan lebih dahulu dan proses menyusul di belakangnya. Kedua baris pada contoh berikut menghitung panjang daftar yang sama dan memberikan hasil yang sama.

fsharp Contoh: dua penulisan yang setara
printfn "%d" (List.length [1; 2; 3])
printfn "%d" ([1; 2; 3] |> List.length)
text Keluaran
3
3

Bentuk kedua lebih mudah dikembangkan karena setiap langkah berikutnya cukup ditambahkan di bawahnya dengan |> baru. Operator ini juga menerima fungsi tanpa nama, ditulis |> fun x -> ..., sehingga langkah kecil yang hanya digunakan sekali dapat menyertai pipeline di tempatnya. Contoh nyatanya, 75 |> float |> fun n -> n / 100.0 mengubah nilai ujian menjadi proporsi dalam dua langkah tanpa satu pun tanda kurung. Pola ini cocok dengan cara membaca kode dari kiri ke kanan, yaitu data lebih dahulu, kemudian proses, dan menghindari tanda kurung yang menumpuk di depan ekspresi. Urutan parameter fungsi koleksi di F#, yang menempatkan data pada argumen terakhir, dirancang agar cocok dipanggil lewat pipeline.

Dari versi bersarang ke versi pipeline#

Transformasi data yang nyata hampir selalu terdiri atas lebih dari satu langkah. Rekap nilai ujian berikut memerlukan tiga langkah, yaitu menyaring nilai yang lulus, menaikkan bobot nilai lulusan, lalu menghitung rata-ratanya. Ditulis tanpa pipeline, ketiga langkah itu menjadi satu ekspresi bersarang yang harus dibaca dari dalam ke luar.

fsharp pipeline-ujian.fsx
// Transformasi nilai ujian: versi bersarang dibanding versi pipeline
let nilai = [80; 45; 75; 90; 60]

let lulus n = n >= 75
let naikkanBobot n = n + 5
let rataRata daftar = List.averageBy float daftar

let versiBersarang = rataRata (List.map naikkanBobot (List.filter lulus nilai))
printfn "Rata-rata versi bersarang : %f" versiBersarang

let versiPipeline =
    nilai
    |> List.filter lulus
    |> List.map naikkanBobot
    |> rataRata
printfn "Rata-rata versi pipeline  : %f" versiPipeline
text Keluaran
Rata-rata versi bersarang : 86.666667
Rata-rata versi pipeline  : 86.666667

Keluaran dari kedua versi identik karena keduanya menjalankan langkah yang sama dalam urutan yang sama. Perbedaannya ada pada bentuk penyajiannya, dan versi pipeline menuliskan data pada baris pertama, kemudian setiap langkah menempati satu baris sesuai urutan pengerjaannya. Membaca versi bersarang menuntut penghitungan tanda kurung, sedangkan membaca versi pipeline hanya menuntut pergerakan mata dari atas ke bawah.

Membaca versi bersarang dimulai dari List.filter lulus yang berada paling dalam, dilanjutkan dengan List.map naikkanBobot, dan diakhiri dengan rataRata pada lapisan terluar. Urutan tersebut kebalikan dari urutan penulisannya, dan jumlah tanda kurung bertambah satu untuk setiap lapisan tambahan. Pada transformasi dengan lima atau enam langkah, bentuk semacam ini sulit diperiksa sekilas dan mudah salah penempatan tanda kurungnya. Apabila fungsi di ruas kanan pipeline memerlukan argumen lain, argumen itu dituliskan setelah fungsi, dan data dari pipeline menempati posisi terakhir sebagaimana terlihat pada setiap baris versi pipeline.

Daftar nilai[80; 45; 75; 90; 60]|>filter lulussisa [80; 75; 90]|>map (+5)[85; 80; 95]|>rata-rata86,7
Alur data pada pipeline rekap nilai ujian, dari daftar asli hingga rata-rata
Diagram di atas menggambarkan aliran data pada versi pipeline, dari daftar asli di kiri hingga hasil akhir di kanan. Setiap kotak mewakili satu langkah bernama, dan setiap panah bertanda |> mewakili satu penerusan nilai. Pola yang sama berlaku untuk fungsi apa pun yang menerima data pada argumen terakhirnya, sehingga pipeline tidak terbatas pada fungsi modul List. Apabila salah satu langkah berubah, langkah lain tidak ikut tersentuh karena ketergantungan hanya lewat nilai yang diteruskan.

Pipeline bernama dengan »#

Komposisi >> menyusun langkah-langkah pipeline menjadi satu fungsi bernama tanpa menyebut data apa pun. Setiap langkah dituliskan sebagai fungsi yang menerima hasil langkah sebelumnya, dan hasil komposisinya adalah fungsi baru yang menunggu data pada saat dipanggil. Bentuk ini memisahkan definisi proses dari penggunaannya, sehingga satu proses dapat digunakan untuk banyak data.

fsharp pipeline-nama.fsx
// Pipeline bernama: komposisi menjadi satu fungsi siap pakai
let lulus n = n >= 75
let naikkanBobot n = n + 5
let rataRata daftar = List.averageBy float daftar

let rekapNilai =
    List.filter lulus
    >> List.map naikkanBobot
    >> rataRata

printfn "Kelas A : %f" (rekapNilai [80; 45; 75; 90; 60])
printfn "Kelas B : %f" (rekapNilai [70; 78; 82; 55])
text Keluaran
Kelas A : 86.666667
Kelas B : 85.000000

Fungsi rekapNilai disusun sekali, lalu digunakan untuk dua daftar nilai yang berbeda dengan hasil masing-masing. Definisi tersebut tidak menyebut daftar apa pun, karena data baru masuk pada saat fungsi dipanggil. Setiap langkahnya berupa penerapan parsial, seperti List.filter lulus yang menyisakan fungsi satu argumen, sehingga tanda >> dapat menyambungkannya tanpa penyesuaian. Urutan fungsi pada komposisinya mengikuti urutan data, sehingga definisi rekapNilai yang ditulis menurun memberikan gambaran proses yang sama dengan versi |> pada bagian sebelumnya. Perannya dibandingkan |> dapat diringkas demikian, yaitu |> menyambungkan nilai yang sudah ada ke fungsi berikutnya, sedangkan >> menyambungkan fungsi dengan fungsi untuk membentuk fungsi baru.

Keduanya sering digunakan bersamaan, yaitu pipeline bernama dibangun dengan >>, lalu data dialirkan ke dalamnya dengan |>. Pemisahan proses dan data ini menjadikan pipeline bernama mudah diuji, karena perilakunya dapat diperiksa pada beberapa masukan kecil sebelum digunakan pada data yang lebih besar.

Ringkasan#

  • x |> f bernilai sama dengan f x, dengan data dituliskan lebih dahulu agar urutan baca mengikuti urutan kerja.
  • Versi pipeline menggantikan ekspresi bersarang dengan baris per langkah, sehingga transformasi dibaca dari atas ke bawah.
  • Komposisi >> membentuk pipeline bernama yang dapat digunakan ulang untuk banyak data, dan |> mengalirkan data ke dalamnya.

Referensi#