Fungsi Kelas Pertama

11

Saya mulai serius melihat Lisp akhir pekan ini (yang saya maksud saya hanya belajar Lisp dan tidak kembali ke proyek dalam C #) dan harus mengatakan saya menyukainya. Saya telah mencoba-coba bahasa fungsional lainnya (F #, Haskell, Erlang) tetapi belum merasakan hasil imbang yang diberikan Lisp kepada saya.

Sekarang ketika saya terus belajar Lisp, saya sudah mulai bertanya-tanya mengapa bahasa non-fungsional tidak mendukung fungsi kelas satu. Saya tahu bahwa bahasa seperti C # dapat melakukan hal serupa dengan delegasi dan sampai batas tertentu Anda dapat menggunakan pointer ke fungsi dalam C / C ++ tetapi apakah ada alasan mengapa ini tidak akan pernah menjadi fitur dalam bahasa tersebut? Apakah ada kelemahan dalam membuat fungsi kelas satu? Bagi saya, ini sangat berguna, jadi saya bingung mengapa lebih banyak bahasa (di luar paradigma fungsional) tidak mengimplementasikannya.

[Sunting] Saya menghargai tanggapannya sejauh ini. Karena saya telah diperlihatkan bahwa banyak bahasa sekarang mendukung fungsi kelas satu sekarang, saya akan mengutarakan kembali pertanyaannya menjadi mengapa perlu waktu lama bagi bahasa untuk mengimplementasikannya? [/ Edit]

Jetti
sumber
3
Saya tidak setuju bahwa C # dapat melakukan "hal serupa". Saya akan mengatakan itu memiliki fungsi kelas satu untuk semua maksud dan tujuan (yang jenis reruntuhan premis Anda). Ini memiliki sintaks untuk fungsi literal, Anda dapat memasukkan fungsi ke dalam variabel, dll.
Logan Capaldo
@Logan - Saya berdebat tentang apakah menyertakan contoh C # tetapi memutuskan untuk didasarkan pada entri wikipedia ini . Menurut entri, tidak ada fungsi kelas benar karena "karena objek yang menyimpan keadaan dinamis fungsi harus dibangun secara manual". Namun, jika itu pernyataan yang salah, saya ingin tahu mengapa! (Lagi pula, aku di sini untuk belajar dan tidak terjebak dengan caraku!)
Jetti
2
entri wikipedia sudah usang. C # modern memberikan lambda yang tepat.
SK-logic
Saya pikir paragraf itu ditulis dengan buruk. Tampaknya mengatakan C + + functors bukan kelas satu, dan tidak juga delegasi C #? Meskipun saya mungkin setuju dengan argumen untuk functors, saya tidak yakin saya akan untuk delegasi C #. Itu juga mengatakan "(lihat lambda mengangkat)", yang merupakan pernyataan tentang bahasa-bahasa ini mendukung penutupan leksikal daripada "berfungsi sebagai nilai". Anda dapat memiliki satu tanpa yang lain. Bahkan jika itu masalahnya, itu tidak benar untuk C #, itu memang memiliki penutupan leksikal. Bagian dari masalahnya adalah "fungsi kelas satu" bisa menjadi istilah yang tidak jelas.
Logan Capaldo
1
@Logan & SK-Logika - Saya menghargai umpan balik Anda dan tetap konstruktif. Saya masih belajar dan sangat menyenangkan untuk tidak dinyalakan, jadi saya menghargai itu. Terima kasih banyak atas komentar dan jawabannya!
Jetti

Jawaban:

5

C #, VB.NET, Python, JavaScript, sekarang bahkan C ++ 0x menyediakan fungsi kelas satu.

Memperbarui:

Implementasi penutupan membutuhkan pengangkatan lambda - suatu teknik yang pada awalnya cukup asing bagi para pemrogram penting. Fungsi kelas satu yang tepat (yang mencakup penutupan) memerlukan setidaknya beberapa dukungan dari runtime dan VM. Butuh beberapa waktu untuk mengadopsi teknik fungsional lama ke dunia imperatif.

Dan, bagian terpenting - fungsi kelas satu hampir tidak dapat digunakan jika tidak ada pengumpulan sampah. Itu diperkenalkan ke pemrograman massal hanya baru-baru ini, dengan Java dan, akibatnya, .NET. Dan pendekatan Java asli adalah untuk menyederhanakan bahasa agar lebih mudah dipahami oleh coders rata-rata. NET pertama kali diikuti, dan baru saja berpisah dari itu (IMHO, cukup dibenarkan dan sesuai) arah.

Semua konsep semacam itu membutuhkan waktu untuk dicerna oleh industri.

Logika SK
sumber
Saya telah mengedit pertanyaan asli berdasarkan jawaban.
Jetti
Fungsi kelas satu! = Penutupan (dan GC jauh lebih penting untuk yang terakhir). Meskipun, ya, mereka terkait erat dan Anda jarang, jika pernah, melihatnya terpisah.
@delnan, tanpa setidaknya beberapa bentuk fungsi penutupan leksikal tidak dapat dikompilasi dan tidak dapat dikonstruksikan dalam run-time, yang wajib untuk definisi fungsi kelas satu.
SK-logic
Tidak. Anda dapat melarang merujuk ke variabel lingkup melampirkan (atau menyalin nilai-nilai variabel yang dirujuk pada saat pembuatan fungsi - tidak tahu apakah ini dianggap sebagai penutupan). Hasilnya tidak terlalu berguna, tetapi fungsi masih dapat dibangun pada saat runtime tanpa penutupan dan oleh karena itu Anda akan memiliki fungsi (aneh) kelas satu.
1
@ SK-logic: C ++ 0x memberikan penutupan tanpa pengumpulan sampah dengan trik yang biasa -> jika variabel keluar dari cakupan dan Anda masih bergantung pada referensi, menggunakan referensi adalah perilaku yang tidak terdefinisi. Jadi itu mungkin ... itu hanya menempatkan honus pada pengembang.
Matthieu M.
5

Fungsi kelas satu jauh lebih menarik tanpa penutup.

Penutupan tidak benar-benar mungkin tanpa semacam manajemen ruang lingkup yang dinamis (pengumpulan sampah). Salah satu hal yang membuat C / C ++ sangat berkinerja tinggi adalah kenyataan bahwa jauh lebih mudah untuk mengkompilasi bahasa tempat Anda mengelola memori secara manual, sehingga agak menghilangkan C / C ++ dari persamaan.

Dan kemudian ya, ada masalah dampak OOP. Anda tidak lagi memiliki pemisahan metode dan properti. Metode itu sendiri adalah properti yang menerima fungsi sebagai nilai. Dalam konteks itu, apa artinya sebenarnya membebani metode karena Anda bisa menukar hal-hal konyol kapan saja. Bisakah Anda benar-benar menambahkan itu ke Jawa, misalnya, tanpa memperkenalkan perubahan paradigma utama ke seluruh bahasa? Di mana kontrak atau rasa (IMO false) orang keamanan dapatkan dari mengetahui konstruksi menjamin itu akan selalu bekerja dengan cara yang sama setiap waktu? Mungkin masuk akal untuk memperlakukan fungsi yang terkait dengan objek sebagai metode sebagai organisme berbeda dalam bahasa yang memungkinkan fungsi untuk ada secara independen di tempat pertama tetapi di Jawa itu bukan pilihan.

Dalam JavaScript, OOP dan fungsional sangat saling terkait dan secara pribadi saya merasa sulit untuk melihat fungsi kelas sebagai apa pun kecuali dibaut dalam bahasa yang tidak ada. Tapi itu membutuhkan sejumlah perubahan paradigma-pergeseran lainnya termasuk tingkat mutabilitas yang tinggi dalam objek dan metode mereka sendiri serta mampu memanggil fungsi seolah-olah mereka adalah anggota dari objek apa pun dengan cepat.

Bahasa tidak hanya alat-set penuh do-hickey untuk menyelesaikan sesuatu untuk sebagian besar. Itu adalah paradigma. Kumpulan ide, strategi, dan opini yang semuanya sejalan dengan cara yang terhubung (atau tampaknya terhubung). Dalam banyak kasus fungsi sebagai kata benda dan kata kerja benar-benar tidak sesuai dengan paradigma sama sekali atau paling tidak cocok.

Yang mengatakan, saya merasa seperti kehilangan lengan ketika dipaksa untuk kode tanpa mereka.

Erik Reppen
sumber
Anda bisa memperlakukan semua metode sebagai tersegel atau hanya menyegel yang paling Anda sayangi, dan Anda akan baik-baik saja.
Alexei Averchenko
@AlexeiAverchenko Saya senang untuk mengatakan saya tidak 100% yakin apa yang Anda maksud dengan itu. Maaf saya ketinggalan komentar Anda sampai sekarang. Googling "metode yang disegel."
Erik Reppen
4

Itu tidak benar-benar mustahil. Tapi ini fitur lain, dan anggaran kerumitannya terbatas. Mungkin dianggap tidak perlu oleh (atau bahkan tidak terjadi) perancang bahasa - "mengapa kita perlu melewati fungsi sekitar? Bahasa ini untuk pemrograman OS!". Mungkin perlu upaya yang signifikan untuk bergabung dengan bagian bahasa lainnya. Misalnya, tipe fungsi mungkin memerlukan tambahan serius pada sistem tipe (mis. Di Jawa), bahkan lebih jika Anda mengalami overloading (terima kasih @Renesis untuk menunjukkannya). Anda juga perlu memberikan beberapa kode pustaka untuk memanfaatkan yang layak - tidak ada yang mau mendefinisikan mapsendiri.

Ini juga bisa membuat tujuan lain dari bahasa lebih sulit dicapai:

  • Menjadi "lebih sulit" untuk dioptimalkan (tidak benar-benar lebih sulit dalam banyak kasus, tetapi membutuhkan pendekatan yang berbeda dari yang biasa Anda lakukan). Misalnya, jika fungsi global dapat dipindahkan, Anda harus membuktikan bahwa ftidak pernah dipindahkan sebelum Anda menyatukannya.
  • Dalam nada yang sama, jika Anda membuat fungsi objek berfitur lengkap, Anda memerlukan kompiler pintar dan JIT untuk menghapus overhead yang terkait dengan itu dan menjadikan pemanggilan sebagai efisien (kecepatan dan ruang-bijaksana) seperti mendorong argumen dan mengembalikan alamat dan melompat ke beberapa alamat.
  • Seperti yang telah disebutkan, ini adalah fitur lengkap lainnya dan langkah pertama menuju mendukung paradigma lain - jika Anda ingin bahasa yang sederhana, mungkin Anda tidak mampu menambahkan fungsi kelas satu tanpa membuang hal-hal lain (yang Anda anggap jauh lebih penting) di luar.
  • Mungkin itu tidak cocok dengan bagian bahasa lainnya. Jika Anda merancang bahasa untuk menjadi inkarnasi terbaik OOP sejak Smalltalk, Anda mungkin ingin fokus pada hal itu alih-alih menawarkan paradigma lain yang sangat berbeda. Terutama jika sulit untuk mengintegrasikan keduanya (lihat di atas). Paradigma N yang dilakukan dengan baik lebih menyenangkan untuk diprogram daripada paradigma N +1 yang dilakukan dengan buruk.

Dalam nada yang sama, orang dapat bertanya mengapa bahasa pemrograman L1 tidak memiliki fitur F dari bahasa L2 yang sangat berbeda.


sumber
1

Saya pikir masalah pertama adalah kesalahpahaman yang Berorientasi Objek dan Fungsional tidak dapat dicampur. Daftar singkat bahasa yang dijelaskan, setidaknya oleh Wikipedia, karena keduanya: JavaScript , ActionScript , Python , C # , F # .

Masalah kedua tampaknya merupakan definisi fungsi kelas satu - mengapa Anda tidak menganggap C # untuk memilikinya, misalnya?

Saya bukan ahli bahasa fungsional, jadi tolong koreksi saya di komentar jika saya salah, tetapi pemahaman saya adalah bahwa dimasukkannya fungsi kelas satu itu sendiri kurang lebih mendefinisikan apakah suatu bahasa mendukung paradigma fungsional .

Apa pertanyaan sebenarnya?

Jadi, memahami bahwa bahasa-bahasa berorientasi objek dapat juga menjadi fungsional, dan bahasa ini mengandung fungsi kelas, kedengarannya seperti pertanyaan yang Anda cari adalah mengapa beberapa bahasa berorientasi objek tidak mengandung fungsi kelas?

Kelebihan fungsi

Salah satu alasan utama untuk ini adalah sulitnya mendefinisikan fungsi-fungsi kelas satu ketika bahasa tersebut juga telah dipilih untuk mendukung fungsi yang berlebihan (contoh di Jawa):

public int dispatchEvent(Event event);
public int dispatchEvent(String event, Object data);

dispatchEventFungsi mana yang akan dirujuk oleh variabel?

Pemrograman berbasis kelas

Pemrograman berbasis kelas tidak mencegah bahasa untuk mendukung objek kelas satu, tetapi dapat membuatnya lebih membingungkan atau menambah pertanyaan yang harus dijawab.

ActionScript, misalnya, sebagai bahasa naskah ECMAS dimulai dengan paradigma yang jauh lebih fungsional seperti JavaScript. Fungsi tidak terikat secara inheren dengan objek, mereka pada dasarnya bisa dipanggil dengan objek apa pun karena ruang lingkup pada saat eksekusi.

Saat Anda menambahkan kelas (non-dinamis), Anda memiliki fungsi yang secara inheren terikat pada turunan, bukan hanya kelas itu sendiri. Ini melempar beberapa kerutan ke dalam spesifikasi Function.applyyang sejujurnya saya belum menggali untuk mengetahui bagaimana mereka mengatasinya.

Nicole
sumber
3
"Dimasukkannya fungsi kelas satu itu sendiri kurang lebih membuat bahasa berfungsi." - salah Itu adalah prasyarat, ya. Tetapi ada banyak lagi, seperti (untuk menyebutkan hanya tiga) menghindari keadaan yang bisa berubah, fokus pada ekspresi dan aplikasi fungsi daripada pernyataan berurutan dan penekanan pada transparansi referensial.
@delnan Anda harus membaca Wikipedia dengan benar ... Kecuali "bahasa fungsional" dan "bahasa yang mendukung paradigma fungsional" adalah dua hal yang berbeda.
Nicole
1
@Rensis: Mereka adalah hal yang berbeda. Anda dapat membuat sesuatu seperti objek (bahkan termasuk vtables) di C, tetapi itu tidak cantik. Beralih dari "memiliki fungsi kelas satu" menjadi "adalah bahasa fungsional" tidak terlalu buruk, tetapi masih ada perbedaan. Juga, wiki (dengan benar) menyatakan pada halaman yang Anda tautkan ke "Fitur-fitur ini adalah keharusan untuk gaya pemrograman fungsional [...]." (yaitu: bukan "fitur penentu") dan mencantumkan beberapa fitur lain pada halaman di FP.
@nannan, Baiklah, saya mengoreksi kata-kata saya. Saya hanya bermaksud agar suatu bahasa dianggap mendukung paradigma fungsional - seperti halnya halaman Wikipedia untuk masing-masing bahasa yang saya daftarkan. Saya tidak bermaksud mengatakan itu saja yang merupakan bagian dari gaya pemrograman fungsional .
Nicole
0

Saya sendiri bertanya-tanya hal yang sama. Setelah saya menggunakan bahasa lambda, saya sering menggunakannya. Bahkan PHP menjadi lebih baik ketika Anda menyadari bahwa Anda dapat melakukan penutupan dengan php 5.3 (tidak sebagus lisp, tetapi masih lebih baik)

Zachary K
sumber