Apa pendapat terkuat Anda terhadap pemrograman fungsional? [Tutup]


25

Pemrograman fungsional adalah salah satu paradigma pemrograman tertua. Namun itu tidak banyak digunakan dalam industri dibandingkan dengan paradigma yang lebih populer. Tetapi sebagian besar ditekankan di dunia akademis.

Apa pendapat terkuat Anda terhadap pemrograman fungsional?


5
LINQ? Delegasi .NET? DSL seperti Mathematica?
Jon Harrop

5
Kebetulan, istilah "pemrograman fungsional" digunakan oleh orang yang berbeda untuk mengartikan hal yang berbeda sehingga Anda perlu mengklarifikasi makna yang Anda gunakan.
Jon Harrop

2
Anda tidak akan pernah menemukan orang untuk kode pada basis kode fungsional Anda. Bukan keputusan bisnis yang bagus, membatasi kumpulan bakat Anda.
Patrick Hughes

Jawaban:


52

Masalahnya adalah bahwa kode yang paling umum secara inheren melibatkan negara - aplikasi bisnis, game, UI, dll. Tidak ada masalah dengan beberapa bagian dari aplikasi yang berfungsi murni; pada kenyataannya sebagian besar aplikasi bisa mendapat manfaat setidaknya dalam satu area. Tetapi memaksakan paradigma di semua tempat terasa kontra-intuitif.


19
Benar. Pemrograman fungsional murni TIDAK cocok untuk aplikasi yang sangat berorientasi negara. Inilah sebabnya saya suka bahasa hibrida yang bisa melakukan keduanya. Gunakan paradigma fungsional untuk masalah fungsional, paradigma imperatif untuk masalah imperatif.
Matt Olenik

8
Sepakat! Negara adalah bagian penting dari pemrograman. Inilah sebabnya mengapa Haskell, dalam beberapa hal yang paling murni dari bahasa FP, memungkinkan penggunaan negara dan IO - itu hanya menegakkan perbedaan antara kode IO / kode negara yang bisa berubah dan kode murni, yang sangat bagus untuk pengujian dan untuk kemudahan pemahaman .
Bill

8
Itu sebabnya saya suka Haskell. Ini mendorong untuk meminimalkan kode stateful tersebut. Dalam OO saya bertujuan untuk menulis yang dapat digunakan kembali, mudah dimengerti dan mudah untuk menguji kode. Sebagian besar waktu saya berakhir dengan kode saya tidak akan menulis jauh berbeda di Haskell.
LennyProgrammers

4
"Ini hanya memberlakukan perbedaan antara kode IO / kode keadaan bisa berubah dan kode murni, yang sangat bagus untuk pengujian". Anda bahkan tidak dapat mencetak pesan debug tanpa melewati sistem tipe atau memperkenalkan monad creep.
Jon Harrop

2
Agaknya program fungsi murni akan membuat dunia sama sekali tidak berubah dengan menjalankannya?
Martin Beckett

24

Masalah dengan pemrograman fungsional bukan pemrograman fungsional itu sendiri - itu sebagian besar orang yang melakukannya dan (lebih buruk) sebagian besar orang yang merancang bahasa untuk melakukannya.

Masalahnya berasal dari fakta bahwa meskipun sangat cerdas (kadang-kadang sangat brilian) terlalu banyak orang hanya sedikit terlalu fanatik tentang kemurnian, kesempurnaan, dan menegakkan pandangan mereka sendiri (sering agak sempit) tentang dunia dan memprogram ke arah bahasa dan semua orang yang menggunakannya.

Salah satu hasilnya adalah kegagalan untuk berkompromi. Ini mengarah (antara lain) ke sekitar 10.000 bahasa dan dialek yang cukup berbeda untuk mengganggu tetapi jarang cukup berbeda bagi seseorang untuk memiliki keunggulan yang benar-benar signifikan daripada yang lain. Banyak juga yang melihat dunia nyata, dan memutuskan bahwa karena tidak cocok dengan model fungsional dengan baik, pada dasarnya itu hanya salah dan sebaiknya diabaikan.

Ketidakmampuan untuk berkompromi juga menyebabkan beberapa bahasa yang benar-benar indah untuk jenis masalah tertentu (atau beberapa jenis masalah tertentu) tetapi sangat menyebalkan bagi banyak orang lain. Beberapa di antaranya mungkin disebabkan oleh model fungsional itu sendiri, tetapi lebih banyak tampaknya (setidaknya bagi saya) disebabkan oleh tipe kepribadian dasar yang tertarik pada bidang ini.

Itu mengarah ke sejumlah masalah. Pertama-tama, belajar "pemrograman fungsional" sebagian besar bernilai filosofis. Dengan sebagian besar jenis bahasa lain, mengetahui satu bahasa dari genre tertentu sangat membantu dalam mempelajari bahasa lain. Jika proyek saya menggunakan bahasa XI biasanya dapat mempekerjakan seseorang yang tahu bahasa Y (tetapi tidak X) dengan cukup aman. Dengan bahasa fungsional, itu jauh kurang benar. Anda mungkin mengenal Erlang dengan sangat baik, tetapi masih menemukan bahwa monumen Haskell benar-benar asing dan tidak dapat dipahami.

Menggabungkan jumlah bahasa dengan portabilitas bakat yang terbatas di antara mereka, dan Anda mendapatkan situasi yang buruk: hampir tidak mungkin bagi satu bahasa atau dialek untuk membentuk "massa kritis" yang diperlukan untuk membuatnya menjadi penggunaan umum yang wajar. Itu perlahan-lahan berubah, tapi masih banyak seperti Linux menjadi desktop OS yang dominan - setiap tahun, orang-orang datang dengan meyakinkan argumen yang akhirnya ini akan menjadi yang tahun - dan seperti orang-orang yang telah memprediksi bahwa setiap tahun selama beberapa dekade sekarang, mereka akan salah lagi. Itu bukan untuk mengatakan bahwa itu (salah satu) tidak akan pernah terjadi - hanya bahwa orang-orang yang melihat prediksi dan berpikir "tidak, tidak tahun ini" telah menjadi orang-orang yang benar sejauh ini.


4
Mungkin akan ada lebih banyak crossover antara bahasa fungsional jika ada lebih banyak bahasa fungsional.
Barry Brown

5
Anda tidak dapat "berfungsi" tanpa kemurnian itu. Setelah Anda melangkahi garis, seluruh konsep berantakan dan Anda berakhir dengan bahasa yang berantakan, paralel, standar tanpa ada keuntungan.
Patrick Hughes

7
Jadi masalah pertama Anda adalah bahwa bahasa fungsional tidak cukup berbeda untuk memiliki keunggulan satu sama lain, dan masalah kedua Anda adalah bahwa mereka terlalu berbeda untuk dengan mudah di antaranya?
Tikhon Jelvis

2
Bagi saya, jawaban ini berbunyi seperti kata-kata kasar. Argumen Anda akan jauh lebih menarik jika Anda memberikan beberapa contoh.
Benjamin Hodgson

1
...roughly 10,000 languages and dialects that are enough different to annoy but only rarely enough different for one to have a truly significant advantage over the others...Tidak, itu kedengarannya seperti semua prosedur prosedural ini. Java, Scala, Kotlin, C ++, C #, Groovy, Cheddar, ES6, Ceylon, Python, daftarnya terus berlanjut - semuanya hanyalah iterasi membosankan dari C yang tidak menyelesaikan masalah nyata. Itulah pendapat ranty saya untuk melengkapi jawaban ranty ini: D
cat

17

Saya pikir alasan mengapa pemrograman fungsional tidak digunakan secara luas adalah karena terlalu banyak menghalangi Anda. Sulit untuk melihat dengan serius, misalnya, Lisp atau Haskell, tanpa mengatakan "seluruh bahasa ini adalah satu inversi abstraksi besar." Saat Anda membuat abstraksi garis dasar yang tidak bisa didapatkan oleh pembuat kode di bawahnya bila diperlukan, Anda menetapkan hal-hal yang tidak bisa dilakukan oleh bahasa tersebut, dan semakin fungsional bahasa itu, semakin banyak kecenderungan yang dimiliki.

Ambil Haskell, misalnya. Atas nama kemurnian fungsional, Anda diharuskan untuk menggunakan inversi abstraksi yang menghancurkan otak yang tidak dipahami oleh siapa pun untuk mengelola keadaan dan I / O, dua bagian paling mendasar dari setiap dan setiap program komputer yang berinteraksi dengan apa pun! Itu menjadi cepat tua.


9
+1, meskipun terkadang saya merasakan hal yang sama ketika saya memprogram dalam bahasa imperatif tingkat tinggi. Sebagai contoh, mengapa fsck saya perlu membuat kelas metode tunggal yang mengimplementasikan antarmuka metode tunggal di Jawa alih-alih hanya menggunakan fungsi pointer seperti yang saya lakukan di C?
dsimcha

14
Saya akan mengatakan itu bukan bahwa Anda "tidak bisa mendapatkan di bawah" abstraksi itu, itu lebih dari itu hanya membutuhkan banyak pekerjaan. Kami terbiasa mengambil pisang dan memakannya dalam bahasa imperatif; Haskell (misalnya) membuat Anda mengisi formulir 20 halaman terlebih dahulu karena memprioritaskan jaminan bahwa pisang tidak akan dimakan secara misterius ketika Anda tidak melihat. Yang membantu ketika beralasan tentang pisang, tetapi kadang-kadang Anda hanya lapar.
j_random_hacker

4
@dsimcha: ini adalah kekhasan Jawa dan bukan tren dalam bahasa imperatif tingkat tinggi. Bahkan, bahasa tingkat tinggi mungkin lebih cenderung memiliki fungsi sebagai objek kelas satu.
Muhammad Alkarouri

3
Perlunya monad di Haskell bukan berasal dari kemurnian fungsional tetapi dari kenyataan bahwa efek samping dan evaluasi malas adalah dua rasa besar yang TIDAK terasa enak bersama. Monads memaksa evaluasi berurutan. (Sungguh, mereka harus disebut Computation Builders atau semacamnya. 'Monad' adalah nama yang buruk untuk siapa pun selain ahli teori kategori.) Dan Anda dapat dengan senang hati melakukan FP tanpa (secara sadar menggunakan) monad!
Frank Shearar

4
Satu hal yang perlu diperhatikan: mengingat "inversi abstraksi" ini, bahasanya mungkin lebih terbatas, tetapi kompiler dan runtime memiliki lebih banyak jaminan tentang kode Anda dan dapat melakukan lebih banyak. Ini seperti pengumpulan sampah - dalam bahasa gc, Anda tidak bisa hanya ruang malloc (yang bisa berguna), tetapi sebagai gantinya, runtime dapat mengatur semua memori Anda, berpotensi lebih efisien daripada yang bisa dilakukan secara manual. Itu sama dengan kemurnian fungsional.
Tikhon Jelvis

8

Dengan segala hormat, saya pikir pertanyaan Anda tidak diajukan. Pemrograman fungsional adalah alat, atau lebih tepatnya seperangkat alat yang berguna untuk memecahkan beberapa jenis masalah. Memiliki pendapat tentang hal itu hanya masuk akal dalam konteks masalah atau aplikasi tertentu. Memiliki pendapat menentangnya secara umum, seperti memiliki pendapat terhadap tang atau kunci pas.


4
Itu poin yang logis secara logis, tetapi bisa diperbaiki dengan menempelkan "untuk jenis masalah pemrograman yang sering Anda temui" ke kalimat terakhir dari pertanyaan OP. (Tidak masalah bahwa masing-masing pembaca akan menghadapi masalah yang berbeda, asalkan mereka menggambarkan siapa mereka.)
j_random_hacker

4

Bahkan jika saya sudah menguasainya, saya mungkin enggan menggunakan bahasa fungsional untuk produk komersial karena alasan sederhana bahwa mereka tidak dipahami secara luas dan jika saya berharap bisnis ini berkembang, saya akan khawatir tentang kemampuan untuk menemukan pengembang lain yang mampu. mempertahankan atau memperluasnya dari waktu ke waktu.

Ini tidak terbayangkan, dan Anda mungkin akan mendapatkan standar pengembang yang lebih tinggi karena lulusan javaschool tanpa keterampilan peretasan yang sebenarnya tidak akan tahu harus mulai dari mana pada proyek semacam itu, tetapi kumpulan pengembang yang terbatas pasti akan menjadi pertimbangan yang diperlukan. dari perspektif bisnis.


2

Waktu ke Pasar

Sulit untuk menghilangkan lanskap IT lengkap dari kode prosedural dan mantra.


1
Program fungsional seringkali lebih mudah untuk diuji. Dan mereka lebih pendek. Sangat tidak setuju. Saya pikir Anda menjawab pertanyaan lain, "Apa pendapat Anda yang paling kuat untuk tidak beralih ke pemrograman funtional?".
Jonas


2

pertama-tama saya tidak menerima argumen tentang pemrograman state-ful dan fp. lihat monad negara di haskell dan Anda akan menemukan sejumlah cara baru yang menarik untuk menilai dampak negara pada kode Anda.

jika saya membuat argumen yang berarti terhadap fp, itu akan berarti bahwa belajar bahasa fungsional yang serius seperti haskell seperti belajar mengendarai mobil formula satu .... menggembirakan dan mendidik, tetapi sayangnya tidak berguna untuk pengkodean industri sehari-hari karena, rata-rata , rekan kerja Anda mengendarai camry dan cukup senang melakukannya. masih sangat sulit untuk menemukan pekerjaan di lingkungan yang ramah fp, dan saya tidak melihat perubahan ini kecuali ada yang mau menyerang sendiri atau mencari beberapa praktisi fp terkenal.

Saya kira jawaban saya menunjukkan saya sebagai fanboy fp. Saya sarankan memberikan bahasa fp nyata seperti haskell putaran serius sebelum khawatir menemukan alasan mengapa Anda tidak harus.


6
Saya pikir paragraf pertama Anda menjelaskan persis apa yang salah dengan pola pikir FP. Kami tidak ingin "cara baru yang menarik untuk menilai dampak negara pada kode kami." Apa artinya itu?!? Kami hanya ingin negara ada di sana dan mudah diakses karena kami membutuhkannya untuk menyelesaikan sesuatu.
Mason Wheeler

2
Camry I drive memiliki masalah, tetapi tidak mengharuskan saya untuk terus memeriksa di bawah kap untuk kebocoran ruang . Haskell lebih seperti bahasa yang terlihat seperti mobil F1, tetapi sebenarnya tidak dapat melakukan putaran tinggi untuk periode waktu yang berkelanjutan. :-P
j_random_hacker

1
@Mason Wheeler: "Kami tidak ingin cara baru yang menarik untuk menilai dampak negara pada kode kami." Sebaliknya, kami lebih suka menghabiskan waktu seminggu melacak bug yang sangat buruk karena efek samping yang tidak diinginkan (saya berbicara dari pengalaman pribadi).
Giorgio

@ brad clawsie: Saya pikir seluruh masalah dalam mengontrol efek samping dalam FP dapat membuat pengkodean menjadi lebih produktif: dibutuhkan waktu lebih lama untuk menulis tetapi sedikit waktu untuk memperbaikinya. Sayangnya seseorang harus berusaha keras untuk belajar terlebih dahulu, dan banyak programmer tidak memiliki pemikiran jangka panjang ini: segala sesuatunya harus dilakukan dengan cepat. Tidak ada waktu untuk melakukannya dengan benar pertama kali, tetapi selalu ada waktu untuk debug dan memperbaikinya nanti. :-)
Giorgio

@Mason Wheeler: Dari sudut pandang fungsional, memiliki status bersama hanya berguna untuk tujuan optimasi: menyalin nilai sekitar membutuhkan terlalu banyak waktu dan memori, sehingga Anda berbagi objek data untuk menghindari penyalinan yang tidak dibutuhkan. Tetapi menegakkan negara bersama sebagai aturan sejak awal adalah semacam optimasi prematur.
Giorgio

2

Saya penggemar berat dan pendukung pemrograman fungsional. Tapi inilah poin saya:

  • mudah dipelajari
    Bahasa pemrograman seperti python dan ruby ​​(dan banyak bahasa lainnya) mudah dipelajari. Pemrograman fungsional tingkat lanjut, dengan bahasa seperti Haskell, Agda, Coq, ATS, dll., Cukup sulit untuk dipelajari. Beberapa menggunakan istilah "pemrograman terstruktur matematika". Sangat mudah jika Anda terbiasa dengan teori kategori dan matematika abstrak, tetapi cukup banyak bekerja jika Anda tidak tahu apa yang disebut sebagai "monad".

  • pemrograman dengan bahasa scripting dapat berarti lebih banyak produktivitas.
    Dalam beberapa situasi menggunakan bahasa scripting seperti python dan ruby ​​dapat menyebabkan lebih banyak produktivitas. Ini berarti membuat prototipe cepat dan menempelkan paket atau pustaka yang berbeda. Bahkan menggunakan bahasa dinamis (misalnya pemrograman berorientasi objek dinamis) dapat menjadi hal yang baik dalam konteks ini. Biasanya pengetikan statis lebih baik, tetapi skrip dengan tipe dinamis dapat memiliki efek positif.

  • pertimbangan bisnis
    Pemrograman hanya sebagian kecil dari proyek perangkat lunak yang sukses. Perangkat lunak harus berfungsi, pengguna harus bahagia dan ini tidak selalu tergantung pada bahasa pemrograman yang digunakan. Manajer harus memikirkan manfaat dan risiko ketika mengevaluasi teknologi baru dan bahasa pemrograman. Bisakah programmer baru belajar dengan cepat bahasa pemrograman baru? Apakah ada pengalaman di perusahaan dengan teknologi? Apakah ada risiko dan akankah ini sulit untuk diperdebatkan dengan manajemen tingkat atas?

Dalam konteks bisnis, pemrograman fungsional dapat digunakan dalam sistem yang menambah komponen perangkat lunak inti, misalnya, komponen yang tidak terlalu kritis terhadap misi. Misalnya bank yang tidak akan mengubah perangkat lunak inti, tetapi tambahkan bagian baru (GUI, perangkat lunak pemantauan, dll.) Dalam bahasa pemrograman baru. (Mungkin ada pengecualian, tapi ini pengalaman saya dengan bank.)

Lebih lanjut, pemrograman fungsional sangat berguna ketika verifikasi formal merupakan manfaat atau keharusan.


3
"mudah dipelajari": Saya tidak menemukan menguasai Haskell lebih sulit daripada menguasai C ++ modern. Saya pikir kita cenderung menganggap keras apa yang tidak kita kenal.
Giorgio

1

Saya tidak menentang FP sebagai paradigma yang bermanfaat, tetapi saya menentangnya sebagai satu-satunya paradigma yang tersedia dalam bahasa pemrograman.

Ini menawarkan keuntungan dalam memecahkan banyak masalah. Namun FP dapat, dan telah, diterapkan dalam bahasa prosedural seperti C.


Setuju dengan kalimat pertama, tidak setuju dengan yang kedua. Anda pada dasarnya tidak dapat melakukan FP tanpa pengumpulan sampah.
dsimcha

Tidak ada persyaratan bahwa sistem runtime bahasa tidak memiliki manajemen memori transparan (dengan pengumpulan sampah) agar sesuai dengan label "prosedural", jadi ironisnya Anda mengucapkan kalimat kedua seperti itu. BASIC adalah salah satu bahasa tersebut.
Huperniketes

"Kamu pada dasarnya tidak bisa melakukan FP tanpa pengumpulan sampah." - Kenapa?
quant_dev

+1 Pemrograman fungsional pada tingkat paling dasar adalah pemrograman stateless. Saya rasa tidak ada bahasa yang bisa melakukan hal ini sampai batas tertentu. Saya sudah menulis fungsi dalam C, C ++, Java, assembly, C #, bahkan Basic. Semua yang diperlukan adalah bahwa fungsi tidak memiliki efek samping atau mempertahankan status antara panggilan.
Michael K

Di sisi lain, jika bahasa Anda sepenuhnya murni, kompiler memiliki lebih banyak kelonggaran dalam pengoptimalannya. Juga, kode menjadi lebih mudah untuk diuji dan dipikirkan. Fungsional secara keseluruhan memang memberikan beberapa manfaat dibandingkan pendekatan hybrid; jika Anda tetap membuat sebagian besar kode Anda tidak memiliki kewarganegaraan, Anda bisa melangkah lebih jauh dan menuai manfaat tambahan.
Tikhon Jelvis

1
  1. (dan sejauh ini yang paling penting) Tenaga kerja programmer tidak terlatih dalam bahasa atau gaya tersebut
  2. Banyak penginjil fungsional datang sebagai lubang atau kue buah karena cara mereka mencoba menjual fungsional. Tidak ada yang suka lubang, dan tidak ada yang akan membuang uang di balik kue buah. Pikiran Anda, saya sangat suka hal-hal fungsional dan ingin menariknya, tetapi saya tahu di tempat kerja saya, saya akan menjadi satu-satunya orang yang dapat mengembangkannya tanpa menghabiskan uang untuk pelatihan (penjualan keras), dan hampir semua yang baik referensi bicara di pembaca.

Fungsional akan muncul ketika kita memiliki ratusan core dan mencapai kesadaran bahwa kunci tidak berskala. Kemudian paralel data bersarang akan menjadi satu-satunya cara untuk pergi untuk program "besi besar", dan fungsional unggul pada saat itu.


0

FP keren di dunia akademis karena keren menulis program pendek yang bagus, sambil mengabaikan kinerja. Tidak ada konspirasi menentangnya di dunia nyata. Juga misalnya menerapkan beberapa hal (radix sort misalnya) sepertinya sakit total di FP. Oh dan kode yang dihasilkan adalah IMHExperience sloooooooooooooooooooooow.


4
Ya, itu sama sekali tidak benar. Kode Haskell biasanya setara dengan C dan Java, dan jauh lebih cepat daripada Python dan teman-teman. Hal ini juga biasanya sepele untuk diparalelkan, berpotensi memberikan kecepatan lebih.
Tikhon Jelvis

0

Beberapa memiliki kurva belajar yang cukup curam, membutuhkan waktu yang lama (terutama jika Anda berasal dari OOP; Anda akan memenggal kepala Anda beberapa kali sebelum mendapatkan perubahan paradigma).

Meskipun saya mulai mendapatkan pemrograman fungsional (datang dari Jawa dan pergi ke Clojure) saya masih merasa cukup sulit. Komunitas sepertinya tidak menulis kode seekspresif Java.

Sepertinya ada sedikit kerugian dalam ekspresif dan sedikit peningkatan kompleksitas.


Saya pikir orang-orang tanpa pengalaman pemrograman sebelumnya akan mengatakan bahwa OOP memiliki kurva belajar yang lebih curam daripada FP, karena FP lebih dekat dengan Matematika. Saya tidak mengerti apa yang Anda maksud dengan "Komunitas sepertinya tidak menulis kode seekspresif Java", apa maksud Anda?
Jonas

Saya tidak pernah mendengar bahasa fungsional kehilangan ekspresif. Tapi saya juga tidak pernah menggunakan bahasa yang kurang ekspresif daripada Java, jadi saya mungkin memiliki definisi "ekspresif" yang berbeda.
glenatron

@Jonas - karena satu hal sederhana: memendekkan nama untuk fungsi, variabel, dll ... maksud saya, mengapa tidak hanya memberi nama untuk apa yang seharusnya atau yang harus mereka lakukan? mengapa "pmap"?
Belun

1
@Belun: Itu tidak ada hubungannya dengan pemrograman fungsional untuk dilakukan. Anda harus merujuk ke bahasa pemrograman tertentu. Peta adalah fungsi yang umum dalam banyak bahasa pemrograman fungsional, dan memiliki nama baik . pmapAnda merujuk mungkin varian parallell.
Jonas

saya berkata "komunitas sepertinya tidak menulis". itu berarti apa yang saya alami dan merujuk pada komunitas yang saya tonton. itu tidak harus berlaku untuk semua, meskipun saya meragukannya. itu memang ada hubungannya dengan pemrograman fungsional, itu seperti gayanya
Belun

0

Meskipun saya memiliki sedikit pengalaman dengan bahasa pemrograman fungsional (saya tahu beberapa Haskell dan Lisp) saya menemukan paradigma FP sangat kuat dan sering lebih elegan daripada paradigma lain. Saya berharap memiliki kesempatan untuk mengerjakan proyek serius menggunakan FP.

Satu-satunya area di mana saya memiliki beberapa keraguan serius mengenai efektivitas FP adalah dalam bagaimana ia dapat menangani struktur data yang kompleks yang tidak dapat didefinisikan secara induktif, misalnya grafik. Sebagai contoh, jika saya harus mengimplementasikan algoritma yang bekerja pada grafik besar, mungkin berjalan melalui grafik dan membuat perubahan lokal kecil, saya bertanya-tanya apakah pendekatan FP dapat cocok dengan pendekatan imperatif di mana program diizinkan untuk bergerak dari node ke simpul menggunakan pointer.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.