Dalam beberapa tahun terakhir fungsi anonim (fungsi lambda AKA) telah menjadi konstruksi bahasa yang sangat populer dan hampir setiap bahasa pemrograman utama / utama telah memperkenalkannya atau direncanakan untuk memperkenalkannya dalam revisi standar yang akan datang.
Namun, fungsi anonim adalah konsep yang sangat tua dan sangat terkenal dalam Matematika dan Ilmu Komputer (ditemukan oleh ahli matematika Alonzo Church sekitar tahun 1936, dan digunakan oleh bahasa pemrograman Lisp sejak 1958, lihat misalnya di sini ).
Jadi mengapa tidak bahasa pemrograman arus utama saat ini (banyak yang berasal 15 hingga 20 tahun yang lalu) mendukung fungsi lambda dari awal dan hanya memperkenalkannya nanti?
Dan apa yang memicu adopsi besar-besaran fungsi anonim dalam beberapa tahun terakhir? Apakah ada peristiwa khusus, persyaratan baru atau teknik pemrograman yang memulai fenomena ini?
CATATAN PENTING
Fokus pertanyaan ini adalah pengenalan fungsi anonim dalam bahasa modern, arus utama (dan karenanya, mungkin dengan beberapa pengecualian, tidak berfungsi). Juga, perhatikan bahwa fungsi anonim (blok) hadir di Smalltalk, yang bukan bahasa fungsional, dan bahwa fungsi yang dinamai normal telah hadir bahkan dalam bahasa prosedural seperti C dan Pascal untuk waktu yang lama.
Tolong jangan terlalu menggeneralisasi jawaban Anda dengan berbicara tentang "adopsi paradigma fungsional dan manfaatnya", karena ini bukan topik pertanyaan.
sumber
Jawaban:
Tentu saja ada kecenderungan yang nyata terhadap pemrograman fungsional, atau setidaknya beberapa aspek tertentu. Beberapa bahasa populer yang pada beberapa titik mengadopsi fungsi anonim adalah C ++ ( C ++ 11 ), PHP ( PHP 5.3.0 ), C # ( C # v2.0 ), Delphi (sejak 2009), Objective C ( blok ) sementara Java 8 akan membawa dukungan untuk lambdas ke bahasa . Dan ada bahasa populer yang umumnya tidak dianggap fungsional tetapi mendukung fungsi anonim sejak awal, atau setidaknya sejak awal, contoh yang bersinar adalah JavaScript.
Seperti halnya semua tren, mencoba mencari satu peristiwa yang memicu mereka mungkin hanya buang-buang waktu, biasanya merupakan kombinasi faktor, yang sebagian besar tidak dapat dikuantifikasi. Lisp Praktis Umum , yang diterbitkan pada tahun 2005, mungkin telah memainkan peran penting dalam membawa perhatian baru kepada Lisp sebagai bahasa praktis , karena untuk beberapa waktu Lisp sebagian besar adalah bahasa yang akan Anda temui dalam lingkungan akademik, atau ceruk pasar yang sangat spesifik. Popularitas JavaScript mungkin juga memainkan peran penting dalam membawa perhatian baru ke fungsi anonim, seperti yang dijelaskan oleh munificent dalam jawabannya .
Selain adopsi konsep-konsep fungsional dari bahasa multi-guna, ada juga perubahan nyata ke bahasa fungsional (atau sebagian besar fungsional). Bahasa-bahasa seperti Erlang (1986), Haskell (1990), OCaml (1996), Scala (2003), F # (2005), Clojure (2007), dan bahkan bahasa-bahasa khusus domain seperti R (1993) tampaknya telah memperoleh pengikut yang kuat dengan kuat setelah mereka diperkenalkan. Tren umum telah membawa perhatian baru pada bahasa fungsional yang lebih tua, seperti Scheme (1975), dan jelas Common Lisp.
Saya pikir satu-satunya peristiwa yang lebih penting adalah adopsi pemrograman fungsional di industri. Saya sama sekali tidak tahu mengapa itu tidak terjadi, tetapi bagi saya tampaknya pada suatu titik selama pemrograman fungsional awal dan pertengahan tahun 90-an mulai menemukan tempatnya di industri, mulai (mungkin) dengan proliferasi Erlang di telekomunikasi dan adopsi Haskell dalam dirgantara dan desain perangkat keras .
Joel Spolsky telah menulis posting blog yang sangat menarik, The Perils of JavaSchools , di mana ia menentang tren (saat itu) universitas untuk lebih menyukai Jawa daripada yang lain, mungkin lebih sulit untuk belajar bahasa. Meskipun posting blog tidak ada hubungannya dengan pemrograman fungsional, ia mengidentifikasi masalah utama:
Aku masih ingat betapa aku membenci Lisp, ketika aku pertama kali bertemu dengannya selama masa kuliahku. Ini jelas nyonya yang kasar, dan itu bukan bahasa di mana Anda bisa segera produktif (well, setidaknya saya tidak bisa). Dibandingkan dengan Lisp, Haskell (misalnya) jauh lebih ramah, Anda dapat menjadi produktif tanpa banyak usaha dan tanpa merasa seperti orang idiot, dan itu mungkin juga menjadi faktor penting dalam pergeseran menuju pemrograman fungsional.
Secara keseluruhan, ini adalah hal yang baik. Beberapa bahasa multi-tujuan mengadopsi konsep paradigma yang mungkin tampak misterius bagi sebagian besar pengguna mereka sebelumnya, dan kesenjangan antara paradigma utama semakin menyempit.
Pertanyaan-pertanyaan Terkait:
Bacaan lebih lanjut:
sumber
Saya pikir ini menarik betapa popularitas pemrograman fungsional telah paralel dengan pertumbuhan dan proliferasi Javascript. Javascript memiliki banyak fitur radikal di sepanjang spektrum pemrograman fungsional yang pada saat penciptaannya (1995) tidak begitu populer di antara bahasa pemrograman mainstream (C ++ / Java). Itu tiba-tiba disuntikkan ke arus utama sebagai satu-satunya bahasa pemrograman web sisi klien. Tiba-tiba banyak programmer hanya perlu tahu Javascript dan karena itu Anda harus tahu sesuatu tentang fitur bahasa pemrograman fungsional.
Saya bertanya-tanya bagaimana bahasa / fitur fungsional populer akan jika bukan karena munculnya tiba-tiba Javascript.
sumber
Penangan event JavaScript dan DOM berarti bahwa jutaan programmer harus belajar setidaknya sedikit tentang fungsi-fungsi kelas satu untuk melakukan interaktivitas apa pun di web.
Dari sana, ini adalah langkah yang relatif singkat untuk fungsi anonim . Karena JavaScript tidak menutup
this
, itu juga sangat mendorong Anda untuk belajar tentang penutupan juga. Dan kemudian Anda emas: Anda memahami fungsi kelas satu anonim yang menutup lingkup leksikal.Setelah Anda merasa nyaman dengan itu, Anda menginginkannya dalam setiap bahasa yang Anda gunakan.
sumber
Ini jelas bukan satu - satunya faktor, tetapi saya akan menunjukkan popularitas Ruby. Tidak mengatakan ini lebih penting daripada salah satu dari enam jawaban yang ada di papan tulis, tetapi saya pikir banyak hal terjadi sekaligus dan itu berguna untuk menyebutkan semuanya.
Ruby bukan bahasa fungsional dan lambdas, prods, dan bloknya terasa kikuk ketika Anda menggunakan sesuatu seperti ML, tetapi faktanya, Ruby mempopulerkan gagasan pemetaan dan pengurangan hingga generasi programmer muda yang meninggalkan Jawa dan PHP untuk hipper padang rumput. Lambdas dalam beberapa bahasa tampaknya bergerak defensif lebih dari apa pun ("Tetap di sini! Kita juga punya itu !!)
Tetapi sintaks blok dan cara mengintegrasikannya dengan .each, .map, .reduce, dan sebagainya memunculkan ide fungsi anonim bahkan jika itu benar-benar sebuah konstruksi sintaksis yang berperilaku seperti coroutine. Dan konversi yang mudah ke proc via & membuatnya menjadi obat gerbang untuk pemrograman fungsional.
Saya berpendapat bahwa programmer Ruby on Rails yang menulis JavaScript sudah dihidupkan untuk melakukan sesuatu dengan gaya fungsional yang ringan. Berpasangan dengan programmer blogging, penemuan Reddit, hacker News, dan Stack Overflow sekitar waktu yang sama, dan ide-ide menyebar lebih cepat melalui Internet daripada yang mereka lakukan di zaman Newsgroup.
TL; DR: Ruby, Rails, JavaScript, blogging, dan Reddit / Hacker News / Stack Overflow mendorong ide-ide fungsional ke pasar massal, jadi semua orang menginginkannya dalam bahasa yang ada untuk mencegah pembelotan lebih lanjut.
sumber
Seperti yang ditunjukkan Yannis , ada sejumlah faktor yang memengaruhi adopsi fungsi tingkat tinggi dalam bahasa yang sebelumnya tidak ada. Salah satu hal penting yang hanya disentuhnya sedikit adalah proliferasi prosesor multi-core dan, dengan itu, keinginan untuk pemrosesan yang lebih paralel dan bersamaan.
Peta / filter / pengurangan gaya pemrograman fungsional sangat ramah terhadap paralelisasi, yang memungkinkan programmer untuk dengan mudah menggunakan banyak core, tanpa menulis kode threading eksplisit.
Sebagai Giorgio mencatat, ada lebih banyak pemrograman fungsional dari sekedar fungsi tingkat tinggi. Fungsi, ditambah peta / filter / mengurangi pola pemrograman, dan imutabilitas adalah inti dari pemrograman fungsional. Bersama-sama hal-hal ini menjadi alat yang kuat untuk pemrograman paralel dan bersamaan. Untungnya, banyak bahasa sudah mendukung beberapa gagasan tentang kekekalan, dan, bahkan jika tidak, pemrogram dapat memperlakukan hal-hal sebagai kekal memungkinkan perpustakaan dan kompiler untuk membuat dan mengelola operasi asinkron atau paralel.
Menambahkan fungsi tingkat tinggi ke bahasa adalah langkah penting untuk menyederhanakan pemrograman bersamaan.
Memperbarui
Saya akan menambahkan beberapa contoh yang lebih rinci untuk mengatasi masalah yang dicatat Loki.
Pertimbangkan kode C # berikut yang melintasi koleksi widget, membuat daftar harga widget baru.
Untuk koleksi besar widget, atau metode CalculateWidgetPrice (Widget) yang intensif secara komputasi, loop ini tidak akan memanfaatkan core yang tersedia dengan baik. Untuk melakukan perhitungan harga pada inti yang berbeda akan membutuhkan programmer untuk secara eksplisit membuat dan mengelola utas, melewati pekerjaan di sekitar, dan mengumpulkan hasilnya bersama-sama.
Pertimbangkan solusi setelah fungsi tingkat tinggi ditambahkan ke C #:
Foreach loop telah dipindahkan ke metode Select, menyembunyikan detail implementasinya. Yang tersisa bagi programmer adalah memberi tahu Pilih fungsi apa yang akan diterapkan pada setiap elemen. Ini akan memungkinkan implementasi Select untuk menjalankan perhitungan dalam parellel, menangani semua masalah sinkronisasi dan manajemen thread tanpa keterlibatan programmer.
Tapi, tentu saja, Select tidak melakukan itu secara paralel. Di situlah immutabilitas masuk. Implementasi Select tidak tahu bahwa fungsi yang disediakan (CalculateWidgets di atas) tidak memiliki efek samping. Fungsi ini dapat mengubah status program di luar tampilan Select dan sinkronisasi, merusak segalanya. Misalnya, dalam hal ini nilai salesTax dapat diubah karena kesalahan. Bahasa fungsional murni memberikan kekekalan, sehingga fungsi Select (peta) dapat mengetahui dengan pasti bahwa tidak ada keadaan yang berubah.
C # mengatasinya dengan menyediakan PLINQ sebagai alternatif untuk Linq. Itu akan terlihat seperti:
Yang memanfaatkan sepenuhnya semua inti dari sistem Anda tanpa manajemen eksplisit dari inti tersebut.
sumber
cause
danperceived affect
tanpa menjelaskancorrelation
. Baris terakhir IMO adalah pertanyaannya; tetapi Anda tidak menjawabnya. Mengapa ini menyederhanakan pemrograman bersamaan.Saya setuju dengan banyak jawaban di sini, tetapi yang menarik adalah bahwa ketika saya belajar tentang lambda dan menerimanya, itu bukan karena alasan apa pun yang disebutkan orang lain.
Dalam banyak kasus, fungsi lambda hanya meningkatkan keterbacaan kode Anda. Sebelum lambdas ketika Anda memanggil metode yang menerima pointer fungsi (atau fungsi, atau mendelegasikan), Anda harus mendefinisikan tubuh fungsi itu di tempat lain, jadi ketika Anda memiliki konstruksi "foreach", pembaca Anda harus melompat ke yang berbeda bagian dari kode untuk melihat apa sebenarnya yang Anda rencanakan untuk dilakukan dengan setiap elemen.
Jika tubuh fungsi yang memproses elemen hanya beberapa baris, saya akan menggunakan fungsi anonim karena sekarang ketika Anda membaca kode, fungsi tetap tidak berubah, tetapi pembaca tidak harus melompat-lompat, seluruh implementasi adalah tepat di depannya.
Banyak teknik pemrograman paralel dan paralelisasi dapat dicapai tanpa fungsi anonim; hanya menyatakan yang biasa dan memberikan referensi untuk itu kapan pun Anda perlu. Tetapi dengan lambdas kemudahan menulis kode dan kemudahan membaca kode sangat meningkat.
sumber
Setelah terlibat dalam sejarah baru-baru ini di sini, saya percaya bahwa salah satu faktor adalah penambahan obat generik ke Java dan .NET. Itu secara alami mengarah ke Func < , > dan abstraksi komputasi yang sangat diketik lainnya (Tugas < >, Async < > dll.)
Di dunia .NET kami menambahkan fitur-fitur ini tepat untuk mendukung FP. Itu memicu serangkaian pekerjaan bahasa yang berhubungan dengan pemrograman fungsional, terutama C # 3.0, LINQ, Rx dan F #. Kemajuan itu mempengaruhi ekosistem lain juga dan masih berlanjut hingga hari ini dalam C #, F # dan TypeScript.
Membantu Haskell bekerja di MSR juga, tentu saja :)
Tentu saja ada banyak pengaruh lain juga (JS tentu saja) dan langkah-langkah ini pada gilirannya dipengaruhi oleh banyak hal lainnya - tetapi menambahkan obat generik ke bahasa-bahasa ini membantu mematahkan ortodoksi OO yang kaku pada akhir 90-an di sebagian besar dunia perangkat lunak dan membantu membuka pintu untuk FP.
Don Syme
ps F # adalah tahun 2003, bukan 2005 - meskipun kami akan mengatakan itu tidak mencapai 1,0 sampai 2005. Kami juga melakukan prototipe Haskell.NET pada 2001-02.
sumber
Ini tidak dimaksudkan untuk menjadi jawaban yang serius, tetapi pertanyaan itu mengingatkan saya pada postingan lucu yang lucu oleh James Iry - A Brief, Incomplete, dan Most Wrong History of Programming Languages yang mencakup frasa berikut:
"Lambdas diturunkan ke ketidakjelasan relatif sampai Jawa membuatnya populer dengan tidak memilikinya."
sumber
Dari apa yang saya lihat sebagian besar jawaban berkonsentrasi pada menjelaskan mengapa pemrograman fungsional secara umum membuatnya kembali dan membuatnya menjadi arus utama. Namun saya merasa ini tidak benar-benar menjawab pertanyaan tentang fungsi anonim pada khususnya, dan mengapa mereka tiba-tiba menjadi sangat populer.
Yang benar-benar mendapatkan popularitas, adalah penutupan . Karena dalam kebanyakan kasus, penutupan adalah fungsi yang dibuang variabel yang dilewati, jelas masuk akal untuk menggunakan sintaks fungsi anonim untuk ini. Dan sebenarnya dalam beberapa bahasa itu satu-satunya cara untuk membuat penutupan.
Mengapa penutupan mendapatkan popularitas? Karena mereka berguna dalam pemrograman event-driven, saat membuat fungsi panggilan balik . Saat ini cara menulis kode klien JavaScript (sebenarnya ini adalah cara menulis kode GUI). Saat ini juga cara penulisan kode back-end yang sangat efisien serta kode sistem, karena kode yang ditulis dalam paradigma yang digerakkan oleh event biasanya asinkron dan non-pemblokiran . Untuk back-end ini menjadi populer sebagai solusi untuk masalah C10K .
sumber
Saya pikir alasannya adalah meningkatnya prevalensi pemrograman konkuren dan terdistribusi, di mana inti pemrograman berorientasi objek (merangkum keadaan berubah dengan objek) tidak lagi berlaku. Dalam kasus sistem terdistribusi, karena ada adalah tidak ada negara bersama (dan perangkat lunak abstraksi dari konsep yang bocor) dan dalam kasus sistem bersamaan, karena benar sinkronisasi akses ke negara bersama telah terbukti rumit dan rawan kesalahan. Artinya, salah satu manfaat utama pemrograman berorientasi objek tidak lagi berlaku untuk banyak program, membuat paradigma berorientasi objek jauh lebih bermanfaat daripada dulu.
Sebaliknya, paradigma fungsional tidak menggunakan keadaan bisa berubah. Oleh karena itu, setiap pengalaman yang kami peroleh dengan paradigma dan pola fungsional lebih cepat ditransfer ke perhitungan bersamaan dan didistribusikan. Dan alih-alih menemukan kembali roda, industri sekarang meminjam pola dan fitur bahasa tersebut untuk memenuhi kebutuhannya.
sumber
Jika dapat menambahkan € 0,02 saya, meskipun saya akan setuju dengan pentingnya JavaScript memperkenalkan konsep, saya pikir lebih dari pemrograman bersamaan saya akan menyalahkan mode pemrograman asinkron saat ini. Ketika melakukan panggilan async (diperlukan dengan halaman web), fungsi anonim sederhana sangat berguna, sehingga setiap programmer web (yaitu, setiap programmer) harus terbiasa dengan konsep tersebut.
sumber
Contoh lain yang sangat tua dari sesuatu yang mirip dengan fungsi anonim / lambdas adalah panggilan-dengan-nama di Algol 60. Namun perlu dicatat bahwa panggilan-dengan-nama lebih dekat dengan melewati makro sebagai parameter daripada melewati fungsi sebenarnya, dan itu lebih rapuh / sulit untuk mengerti sebagai hasilnya.
sumber
Di sini nenek moyang yang terbaik dari pengetahuan saya.
sumber
Fungsi anonim bagus karena memberi nama hal-hal itu sulit, dan jika Anda hanya menggunakan fungsi di satu tempat, itu tidak memerlukan nama.
Fungsi Lambda baru saja menjadi arus utama karena sampai saat ini, sebagian besar bahasa tidak mendukung penutupan.
Saya akan menyarankan bahwa Javascript telah mendorong arus utama ini. Ini adalah bahasa universal yang tidak memiliki cara untuk mengekspresikan paralelisme, dan fungsi anonim memudahkan penggunaan model panggilan balik. Selain itu bahasa populer seperti Ruby dan Haskell telah berkontribusi.
sumber