Apakah pemrograman fungsional meningkatkan 'kesenjangan representasional' antara masalah dan solusi? [Tutup]

18

Karena bahasa mesin (misalnya, 0110101000110101) bahasa komputer umumnya berevolusi ke bentuk abstraksi yang lebih tinggi, umumnya membuatnya lebih mudah untuk memahami kode ketika diterapkan pada masalah. Assembler adalah abstraksi atas kode mesin, C adalah abstraksi atas assembler, dll.

Desain berorientasi objek tampaknya sangat baik dalam memungkinkan kita untuk memodelkan masalah dalam hal objek, misalnya, masalah sistem pendaftaran program universitas dapat dimodelkan dengan Coursekelas, Studentkelas, dll. Kemudian, ketika kita menulis solusinya dalam bahasa OO, kami memiliki kelas serupa yang mendapatkan tanggung jawab dan yang umumnya bermanfaat untuk desain, terutama untuk memodulasi kode. Jika saya memberikan masalah ini kepada 10 tim independen yang menyelesaikannya dengan metode OO, umumnya 10 solusi akan memiliki kelas yang berkaitan dengan masalah yang sama. Mungkin ada banyak perbedaan ketika Anda mulai masuk ke dalam penggabungan dan interaksi dari kelas-kelas tersebut, sehingga tidak ada yang namanya "kesenjangan representasi nol."

Pengalaman saya dengan Pemrograman Fungsional sangat terbatas (tidak ada penggunaan dunia nyata, hanya program jenis Hello World). Saya gagal melihat bagaimana bahasa tersebut memungkinkan pemetaan solusi FP dengan mudah ke masalah (dengan kesenjangan representasi yang rendah) seperti yang dilakukan bahasa OO.

Saya mengerti keuntungan FP sehubungan dengan pemrograman bersamaan. Tetapi apakah saya kehilangan sesuatu, atau apakah FP bukan tentang mengurangi kesenjangan representasional (membuat solusi lebih mudah dipahami)?

Cara lain untuk bertanya: apakah kode FP dari 10 tim berbeda yang menyelesaikan masalah dunia nyata yang sama memiliki banyak kesamaan?


Dari Wikipedia tentang Abstraksi (ilmu komputer) (penekanan pada saya):

Bahasa pemrograman fungsional umumnya menunjukkan abstraksi yang terkait dengan fungsi , seperti abstraksi lambda (membuat istilah menjadi fungsi beberapa variabel), fungsi orde tinggi (parameter adalah fungsi), abstraksi braket (membuat istilah menjadi fungsi dari variabel).

Kesenjangan representasional dapat berpotensi meningkat, karena [beberapa] masalah dunia nyata tidak dimodelkan dengan mudah dengan abstraksi semacam itu.


Cara lain yang saya lihat mengurangi kesenjangan representasional adalah dalam menelusuri elemen solusi kembali ke masalah. Kode 0's' dan ' in ' 1sangat sulit dilacak, sedangkan Studentkelasnya mudah dilacak. Tidak semua kelas OO melacak dengan mudah ke ruang masalah, tetapi banyak yang melakukannya.

Bukankah abstraksi FP selalu perlu dijelaskan untuk mencari tahu bagian mana dari ruang masalah yang mereka selesaikan (selain dari masalah matematika )?OK - saya bagus di bagian ini. Setelah melihat lebih banyak contoh, saya melihat bagaimana abstraksi FP sangat jelas untuk bagian masalah yang diekspresikan dalam pemrosesan data.


Jawaban yang diterima untuk pertanyaan terkait Bisakah UML digunakan untuk memodelkan program Fungsional? - mengatakan "Programer fungsional tidak memiliki banyak kegunaan untuk diagram." Saya benar-benar tidak peduli apakah itu UML, tapi itu membuat saya bertanya-tanya tentang abstraksi FP menjadi mudah dimengerti / dikomunikasikan, jika tidak ada diagram yang banyak digunakan (dengan asumsi jawaban ini benar). Sekali lagi, tingkat penggunaan / pemahaman FP saya sepele, jadi saya mengerti tidak perlu diagram pada program FP sederhana.

Desain OO memiliki fungsi / kelas / tingkat paket abstraksi, dengan enkapsulasi (kontrol akses, penyembunyian informasi) di masing-masing, yang membuat pengelolaan kompleksitas menjadi lebih mudah. Ini adalah elemen yang memungkinkan pergi dari masalah ke solusi dan kembali dengan lebih mudah.


Banyak jawaban berbicara tentang bagaimana analisis dan desain dilakukan dalam FP dengan cara yang analog dengan OO, tetapi tidak ada yang mengutip apa pun tingkat tinggi sejauh ini (paul mengutip beberapa hal menarik, tetapi tingkat rendah). Saya melakukan banyak Googling kemarin dan menemukan beberapa diskusi yang menarik. Berikut ini adalah dari Program Fungsional Refactoring oleh Simon Thompson (2004) (penekanan tambang)

Dalam mendesain sistem berorientasi objek, dapat diterima bahwa desain akan mendahului pemrograman. Desain akan ditulis menggunakan sistem seperti UML yang didukung dalam alat-alat seperti Eclipse. Pemrogram pemula mungkin belajar pendekatan desain visual menggunakan sistem seperti BlueJ. Pekerjaan pada metodologi serupa untuk pemrograman fungsional dilaporkan dalam FAD: Analisis Fungsional dan Desain , tetapi sedikit pekerjaan lain yang ada. Mungkin ada sejumlah alasan untuk ini.

  • Program fungsional yang ada adalah skala yang tidak memerlukan desain. Banyak program fungsional kecil, tetapi yang lain, seperti Glasgow Haskell Compiler, substansial.

  • Program fungsional secara langsung memodelkan domain aplikasi, sehingga membuat desain tidak relevan. Sementara bahasa fungsional memberikan berbagai abstraksi yang kuat, sulit untuk membantah bahwa ini menyediakan semua dan hanya abstraksi yang diperlukan untuk memodelkan dunia nyata.

  • Program fungsional dibangun sebagai serangkaian prototipe yang berkembang.

Dalam tesis PhD yang dikutip di atas , manfaat menggunakan Analisis dan metodologi desain (ADM) diuraikan secara independen dari paradigma. Tetapi argumen dibuat bahwa ADM harus sejajar dengan paradigma implementasi. Artinya, OOADM bekerja paling baik untuk pemrograman OO dan tidak diterapkan dengan baik pada paradigma lain seperti FP. Berikut adalah kutipan yang bagus yang saya pikir memparafrasekan apa yang saya sebut kesenjangan representasional:

kita dapat berdebat panjang lebar tentang paradigma mana yang memberikan dukungan terbaik untuk pengembangan perangkat lunak, tetapi seseorang mencapai paket pengembangan yang paling alami, efisien dan efektif ketika seseorang tetap berada dalam paradigma tunggal mulai dari deskripsi masalah hingga implementasi dan pengiriman.

Berikut adalah set diagram yang diusulkan oleh FAD:

  • diagram ketergantungan fungsi yang menyajikan fungsi dengan yang digunakannya dalam implementasinya;
  • type dependency diagram yang menyediakan layanan yang sama untuk tipe; dan,
  • diagram dependensi modul yang menyajikan tampilan arsitektur modul sistem.

Ada studi kasus di bagian 5.1 dari tesis FAD, yang merupakan sistem untuk mengotomatisasi produksi data yang berkaitan dengan liga sepak bola. Persyaratannya adalah 100% fungsional, misalnya, memasukkan hasil sepak bola, menghasilkan tabel liga, tabel penilaian, tabel kehadiran, mentransfer pemain antar tim, memperbarui data setelah hasil baru, dll. Tidak disebutkan bagaimana FAD bekerja untuk menyelesaikan persyaratan non-fungsional didokumentasikan , selain menyatakan bahwa "fungsionalitas baru harus diizinkan dengan biaya minimal", sesuatu yang hampir mustahil untuk diuji.

Sayangnya, terlepas dari FAD, saya tidak melihat referensi modern untuk bahasa pemodelan (visual) yang diusulkan untuk FP. UML adalah paradigma lain, jadi kita harus melupakannya.

Fuhrmanator
sumber
1
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
maple_shaft

Jawaban:

20

Data dasar terstruktur sama dalam hampir semua paradigma. Anda akan memiliki Student, sebuah Course, dll apakah itu sebuah objek, struct, catatan, atau apa pun. Perbedaannya dengan OOP bukanlah bagaimana data terstruktur, melainkan bagaimana fungsinya terstruktur.

Saya benar-benar menemukan program fungsional yang jauh lebih cocok dengan cara saya berpikir tentang masalah. Misalnya, untuk merencanakan jadwal siswa untuk semester depan, Anda berpikir tentang hal-hal seperti daftar kursus yang telah diselesaikan siswa, kursus dalam program gelar siswa, kursus yang ditawarkan semester ini, kursus yang telah diselesaikan siswa dengan prasyarat, kursus dengan waktu yang tidak konflik, dll.

Tiba-tiba, tidak jelas kelas mana yang harus membuat dan menyimpan semua daftar ini. Apalagi ketika Anda memiliki kombinasi kompleks dari daftar ini. Namun, Anda harus memilih satu kelas.

Di FP, Anda menulis fungsi yang mengambil siswa dan daftar kursus dan mengembalikan daftar kursus yang difilter. Anda dapat mengelompokkan semua fungsi tersebut bersama-sama dalam sebuah modul. Anda tidak harus memasangkannya dengan satu kelas atau yang lain.

Jadi model data Anda pada akhirnya tampak lebih seperti bagaimana programmer OOP memikirkan model mereka, sebelum mereka tercemar dengan kelas yang tidak memiliki tujuan lain selain menyediakan tempat yang nyaman untuk meletakkan fungsi yang beroperasi pada kombinasi kelas lain. Tidak ada CourseStudentFilterListkelas aneh atau serupa yang Anda selalu butuhkan di OOP, tetapi tidak pernah memikirkan desain awal.

Karl Bielefeldt
sumber
5
@ BenAaronson masalah dalam pengalaman saya adalah bahwa maka fungsi apa pun yang terkait dengan siswa ditambahkan ke kelas Siswa dan tanggung jawabnya tumbuh dan berkembang sampai Anda perlu memperkenalkan StudentCourseFiltereruntuk menjaga hal-hal dapat dikelola
AlexFoxGill
3
@Den Hybrid memiliki kelebihan. Namun, tidak benar bahwa perbedaannya adalah buatan. Ada banyak kompromi yang harus dilakukan oleh Scala agar sesuai dengan OOP dan FP (inferensi tipe yang kurang kuat adalah satu. Kompleksitas adalah yang lain: ya, bahasa yang menggabungkan OOP dan FP cenderung lebih kompleks - seperti dalam "sulit digunakan dan memahami "- dari salah satu saudara yang lebih murni pada dua ekstrem).
Andres F.
3
@Den Lihat juga pemrograman "'Paling Fungsional' Erik Meijer tidak bekerja" , yang menentang pendekatan hibrida dan untuk menjalankan FP "fundamentalis" penuh.
Andres F.
4
@Den Popularitas yang Anda gambarkan adalah, saya khawatir, sebuah kecelakaan sejarah. Saya menggunakan Scala di tempat kerja, dan ini adalah binatang yang kompleks karena cara mencoba untuk mencampur FP dan OOP. Beralih ke bahasa FP sejati seperti Haskell terasa seperti menghirup udara segar - dan saya juga tidak berbicara dari perspektif akademis!
Andres F.
3
@Den, saya tidak tahu apa fungsi-fungsi itu. Namun, saya dapat memberi tahu Anda jika fungsi pertama di FP adalah semacam atau filter, itu akan bernama filter atau semacam , bukan func(seperti yang Anda beri nama IFilter, dll). Secara umum, di FP Anda akan menamainya funcatau fketika salah satu sortatau filterpilihan yang valid! Sebagai contoh, saat menulis fungsi tingkat tinggi yang diambil funcsebagai parameter.
Andres F.
10

Ketika saya mengambil kelas Java saya bertahun-tahun yang lalu, kami diharapkan menunjukkan solusi kami untuk seluruh kelas, jadi saya harus melihat bagaimana orang berpikir; bagaimana mereka memecahkan masalah secara logis. Saya sepenuhnya mengharapkan solusi untuk mengelompokkan sekitar tiga atau empat solusi umum. Sebagai gantinya, saya menyaksikan 30 siswa memecahkan masalah dengan 30 cara yang sangat berbeda.

Tentu saja, ketika programmer pemula mendapatkan pengalaman, mereka akan mendapatkan paparan pola perangkat lunak umum, mulai menggunakan pola-pola itu pada kode mereka, dan kemudian solusi mereka mungkin menyatu di sekitar beberapa strategi optimal. Pola-pola ini membentuk bahasa teknis dimana pengembang berpengalaman dapat berkomunikasi.

Bahasa teknis yang menopang pemrograman fungsional adalah matematika . Dengan demikian, masalah yang paling cocok untuk diselesaikan dengan menggunakan pemrograman fungsional pada dasarnya adalah masalah matematika. Dengan matematika, saya tidak mengacu pada jenis matematika yang akan Anda lihat dalam solusi bisnis, seperti penambahan dan pengurangan. Sebaliknya, saya berbicara tentang jenis matematika yang mungkin Anda lihat di Math Overflow, atau jenis matematika yang akan Anda lihat di mesin pencari Orbitz (ditulis dalam Lisp).

Orientasi ini memiliki beberapa konsekuensi penting bagi programmer fungsional yang mencoba memecahkan masalah pemrograman dunia nyata:

  1. Pemrograman fungsional lebih bersifat deklaratif daripada keharusan; itu menyangkut dirinya sendiri terutama dengan memberi tahu komputer apa yang harus dilakukan, bukan bagaimana melakukannya.

  2. Program berorientasi objek seringkali dibangun dari atas ke bawah. Desain kelas dibuat, dan detailnya diisi. Program fungsional sering dibangun dari bawah ke atas, dimulai dengan fungsi kecil dan terperinci yang digabungkan menjadi fungsi tingkat yang lebih tinggi.

  3. Pemrograman fungsional dapat memiliki keuntungan untuk prototyping logika kompleks, membangun program fleksibel yang dapat mengubah dan berkembang secara organik, dan membangun perangkat lunak di mana desain awal tidak jelas.

  4. Program berorientasi objek dapat lebih cocok untuk domain bisnis karena kelas, pesan antar objek, dan pola perangkat lunak semuanya menyediakan struktur yang memetakan ke domain bisnis, menangkap kecerdasan bisnisnya, dan mendokumentasikannya.

  5. Karena semua perangkat lunak praktis menghasilkan efek samping (I / O), bahasa pemrograman yang murni fungsional memerlukan mekanisme untuk menghasilkan efek samping tersebut sambil tetap murni secara matematis (monad).

  6. Program fungsional dapat lebih mudah dibuktikan, karena sifat matematikanya. Sistem tipe Haskell dapat menemukan hal-hal pada waktu kompilasi yang sebagian besar bahasa OO tidak bisa.

Dan seterusnya. Seperti banyak hal dalam komputasi, bahasa berorientasi objek dan bahasa fungsional memiliki pengorbanan yang berbeda.

Beberapa bahasa OO modern telah mengadopsi beberapa konsep pemrograman fungsional yang berguna, sehingga Anda dapat memiliki yang terbaik dari kedua dunia. Linq, dan fitur bahasa yang ditambahkan untuk mendukungnya, adalah contoh yang bagus untuk itu.

Robert Harvey
sumber
6
@thepacker: Anda memang memiliki status pemrograman fungsional. Hanya representasi yang berbeda: di OOP Anda menggunakan variabel yang bisa berubah, sedangkan dalam pemrograman fungsional Anda bisa menggunakan aliran status tak terbatas yang dibuat dengan cepat saat program perlu memeriksanya. Sayangnya, state sering diidentifikasi dengan variabel yang dapat berubah, seolah-olah variabel yang dapat diubah adalah satu-satunya cara untuk mewakili negara. Sebagai konsekuensinya, banyak yang percaya bahwa bahasa pemrograman tanpa variabel yang dapat berubah tidak dapat memodelkan keadaan.
Giorgio
12
"Oleh karena itu, masalah yang paling cocok untuk diselesaikan dengan menggunakan pemrograman fungsional pada dasarnya adalah masalah matematika.": Saya tidak setuju dengan pernyataan ini (lihat juga komentar saya sebelumnya), setidaknya saya tidak melihat mengapa itu harus benar atau apa sebenarnya berarti. Anda dapat melihat melintasi struktur direktori sebagai masalah matematika dan mengimplementasikannya dengan fungsi rekursif, tetapi karena pelanggan tidak melihat kode sumber, Anda hanya memecahkan masalah praktis seperti menemukan file di suatu tempat di sistem file. Saya menemukan perbedaan antara masalah matematika dan non-matematika buatan.
Giorgio
5
+1, tapi saya tidak dijual pada poin 2 dan 4. Saya telah melihat banyak tutorial dan posting blog Haskell yang dimulai dengan mengatasi masalah top-down, mendefinisikan semua jenis dan operasi untuk melihat bagaimana semuanya cocok bersama sementara meninggalkan setiap nilai dan definisi fungsi tidak terdefinisi (well, didefinisikan untuk melempar pengecualian). Menurut saya, programmer Haskell cenderung memodelkan masalah dengan lebih teliti karena mereka lebih cenderung menambahkan tipe-tipe sepele demi semantik - misalnya menambahkan SafeStringtipe untuk mewakili string yang telah di-HTML-lolos - dan umumnya melacak lebih banyak efek.
Doval
4
"Masalah yang paling cocok untuk diselesaikan dengan menggunakan pemrograman fungsional pada dasarnya adalah masalah matematika." kenyataan itu tidak benar. Fakta bahwa konsep Monads berasal dari teori kategori juga tidak berarti bahwa tugas matematika adalah domain yang paling alami / cocok untuk bahasa fungsional. Semua itu berarti bahwa kode yang ditulis dalam bahasa fungsional yang sangat diketik dapat dijelaskan, dianalisis, dan beralasan tentang penggunaan matematika. Ini adalah fitur ekstra yang kuat, bukan sesuatu yang menghentikan Anda menulis "Barbie Horse Adventures" di Haskell.
kuncinya
6
@itsbruce Barbie Horse Adventures adalah simulasi matematis serius dari kaliber tertinggi, itu pidgeon holing FP menjadi proyeksi numerik yang terlalu rumit seperti matriks yang menggambarkan kerutan fisik rambut Barbie selama periode diskrit dalam berbagai kemungkinan lingkungan dunia nyata yang meyakinkan orang untuk sepenuhnya menganggapnya tidak relevan dengan pengkodean masalah bisnis sehari-hari mereka.
Jimmy Hoffa
7

Saya ingin menekankan aspek yang saya anggap penting dan belum tercakup dalam jawaban lainnya.

Pertama-tama, saya berpikir bahwa kesenjangan representasional antara masalah dan solusi bisa lebih di benak programmer, sesuai dengan latar belakang mereka dan konsep-konsep yang lebih mereka kenal.

OOP dan FP melihat data dan operasi dari dua perspektif yang berbeda dan memberikan pengorbanan yang berbeda, seperti yang telah ditunjukkan oleh Robert Harvey.

Salah satu aspek penting di mana mereka berbeda adalah cara mereka mengizinkan untuk memperluas perangkat lunak Anda.

Pertimbangkan situasi di mana Anda memiliki kumpulan tipe data dan kumpulan operasi, misalnya Anda memiliki format gambar yang berbeda dan Anda memelihara perpustakaan algoritma untuk memproses gambar.

Pemrograman fungsional membuatnya lebih mudah untuk menambahkan operasi baru ke perangkat lunak Anda: Anda hanya perlu perubahan lokal dalam kode Anda, yaitu Anda menambahkan fungsi baru, yang menangani berbagai format data input. Di sisi lain, menambahkan format baru lebih terlibat: Anda perlu mengubah semua fungsi yang sudah Anda implementasikan (perubahan non lokal).

Pendekatan berorientasi objek simetris dengan ini: setiap tipe data membawa implementasi sendiri dari semua operasi dan bertanggung jawab untuk memilih implementasi yang tepat saat runtime (pengiriman dinamis). Ini membuatnya mudah untuk menambahkan tipe data baru (mis. Format gambar baru): Anda cukup menambahkan kelas baru dan mengimplementasikan semua metodenya. Di sisi lain, menambahkan operasi baru berarti mengubah semua kelas yang perlu menyediakan operasi itu. Dalam banyak bahasa ini dilakukan dengan memperluas antarmuka dan mengadaptasi semua kelas yang mengimplementasikannya.

Pendekatan berbeda terhadap ekstensi ini adalah salah satu alasan mengapa OOP lebih sesuai untuk masalah tertentu di mana rangkaian operasi lebih jarang bervariasi dibandingkan dengan set tipe data tempat operasi ini bekerja. Sebuah contoh khas adalah GUI: Anda memiliki satu set tetap operasi bahwa semua widget harus menerapkan ( paint, resize, move, dan sebagainya) dan kumpulan widget yang Anda ingin memperpanjang.

Jadi, menurut dimensi ini, OOP dan FP hanyalah dua cara specular untuk mengatur kode Anda. Lihat SICP , khususnya Bagian 2.4.3, Tabel 2.22, dan paragraf yang disampaikan .

Meringkas: di OOP Anda menggunakan data untuk mengatur operasi, di FP Anda menggunakan operasi untuk mengatur data. Setiap pendekatan lebih kuat atau lebih lemah sesuai dengan konteksnya. Secara umum, tidak satu pun dari keduanya memiliki kesenjangan representasional yang lebih tinggi antara masalah dan solusi.

Giorgio
sumber
1
Sebenarnya, Pola Pengunjung (dalam OOP) memberi Anda kekuatan yang sama seperti yang Anda katakan untuk FP. Ini memungkinkan Anda untuk menambahkan operasi baru sambil membuat menambah kelas baru lebih sulit. Saya ingin tahu apakah Anda dapat melakukan hal yang sama di FP (mis. Menambahkan format baru alih-alih operasi).
Euforia
1
Skenario pemrosesan gambar sepertinya bukan contoh terbaik. Tentunya Anda akan mengonversi gambar menjadi beberapa format dan proses internal yang alih-alih menulis implementasi terpisah dari semua hal pemrosesan gambar Anda untuk setiap jenis gambar?
Hei
1
@Giorgio mungkin saya tidak mendapatkan makna yang dimaksudkan dari bagian ini: "menambahkan format baru lebih terlibat: Anda perlu mengubah semua fungsi yang sudah Anda terapkan."
Hei,
2
@ Hei Giorgio sepertinya merujuk pada apa yang disebut Masalah Ekspresi . "Menambahkan format baru" berarti "menambahkan konstruktor baru (alias 'kasing') ke tipe data".
Andres F.
1
@ Euphoric: Saya belum melihat detailnya, tetapi padanan FP dengan pola pengunjung harus melibatkan Othervarian / konstruktor dalam tipe data Anda, dan parameter fungsi ekstra untuk diteruskan ke semua fungsi untuk menangani kasus lainnya . Tentu saja canggung / kurang alami sehubungan dengan solusi OOP (pengiriman dinamis). Dengan cara yang sama, pola pengunjung canggung / kurang alami daripada solusi FP (fungsi tingkat tinggi).
Giorgio
5

Sebagian besar bahasa fungsional tidak Berorientasi Objek. Itu tidak berarti mereka tidak memiliki objek (dalam arti tipe kompleks yang memiliki fungsi spesifik yang terkait dengannya). Haskell, seperti java, memiliki Daftar, Peta, Array, semua jenis Pohon dan banyak jenis kompleks lainnya. Jika Anda melihat modul Daftar Haskell atau Peta, Anda akan melihat serangkaian fungsi yang sangat mirip dengan metode di sebagian besar modul perpustakaan bahasa OO. Jika Anda memeriksa kode, Anda bahkan akan menemukan enkapsulasi yang serupa, dengan beberapa tipe (atau konstruktornya, tepatnya) dan fungsinya hanya dapat digunakan oleh fungsi-fungsi lain dalam modul.

Cara Anda bekerja dengan tipe-tipe ini di Haskell seringkali tidak jauh berbeda dari cara OO. Di Haskell saya katakan

  null xs
  length xs

dan di Jawa Anda katakan

  xs.isEmpty
  xs.length

Tomat, tomat. Fungsi Haskell tidak terikat pada objek tetapi mereka terkait erat dengan tipenya. ¨Ah, tapi , ¨ kamu bilang, ¨ di Jawa itu memanggil metode mana yang panjangnya sesuai dengan kelas sebenarnya dari objek itu¨. Kejutan - Haskell juga melakukan polimorfisme dengan kelas tipe (dan hal-hal lain).

Di Haskell, jika saya punya adalah - kumpulan bilangan bulat - tidak masalah apakah koleksi itu daftar atau set atau larik, kode ini

  fmap (* 2) is

akan mengembalikan koleksi dengan semua elemen digandakan. Polimorfisme berarti bahwa fungsi peta yang sesuai untuk tipe spesifik akan dipanggil.

Contoh-contoh ini, sebenarnya, bukan tipe yang benar-benar kompleks tetapi hal yang sama berlaku pada masalah yang lebih sulit. Gagasan bahwa bahasa fungsional tidak memungkinkan Anda memodelkan objek yang rumit dan mengaitkan fungsionalitas tertentu dengannya sangat salah.

Ada yang perbedaan penting dan signifikan antara gaya fungsional dan OO tapi saya tidak berpikir jawaban ini harus berurusan dengan mereka. Anda bertanya apakah bahasa fungsional mencegah (atau menghambat) pemodelan intuitif masalah dan tugas. Jawabannya adalah tidak.

itu otaknya
sumber
Sebenarnya, Anda bisa menggunakan kelas tipe di Java / C #; Anda hanya secara eksplisit melewati kamus fungsi, alih-alih membuat kompiler menyimpulkan yang benar berdasarkan jenisnya.
Doval
Oh, tentu saja. Seperti yang dikatakan William Cook, banyak kode OO yang lebih sering menggunakan fungsi tatanan lebih tinggi daripada kode fungsional, meskipun koder mungkin tidak menyadarinya.
kuncinya
2
Anda membuat perbedaan yang salah. Daftar tidak lebih dari struktur data lembam dari tumpukan atau antrian atau simulator tic-tac-toe. Daftar dapat menampung apa saja (dalam Haskell itu mungkin sebagian fungsi yang diterapkan) dan mendefinisikan bagaimana hal-hal itu dapat berinteraksi dengan. Anda bisa menerapkan daftar penuh fungsi yang diterapkan sebagian ke daftar nilai lainnya dan hasilnya adalah daftar baru yang berisi setiap kombinasi fungsi yang mungkin dari yang pertama dan input dari yang kedua. Itu jauh lebih dari sebuah struct C.
kuncinya
3
Jenis digunakan untuk hal-hal yang lebih bervariasi dalam bahasa fungsional daripada yang imperatif / OO (jenis sistem cenderung lebih kuat dan konsisten, untuk satu hal). Jenis dan fungsinya digunakan untuk membentuk jalur kode (itulah sebabnya beberapa bahasa fungsional tidak memiliki kata kunci untuk loop - tidak diperlukan), misalnya.
kuncinya
4
@Fuhrmanator "Saya tidak melihat bagaimana ini dilakukan di FP" Jadi Anda mengeluh sesuatu yang Anda tidak mengerti tidak masuk akal; pergi mempelajarinya, memahaminya secara menyeluruh, dan kemudian akan masuk akal. Mungkin setelah masuk akal Anda akan memutuskan itu omong kosong dan Anda tidak perlu orang lain untuk membuktikannya kepada Anda, meskipun orang lain seperti di atas memahaminya dan belum sampai pada kesimpulan itu. Anda tampaknya membawa pisau ke pertarungan senjata, dan sekarang Anda memberi tahu semua orang bahwa senjata tidak berguna karena tidak tajam.
Jimmy Hoffa
4

FP memang berupaya untuk mengurangi kesenjangan representasional:

Sesuatu yang Anda akan melihat banyak dalam bahasa fungsional adalah praktik membangun bahasa (menggunakan desain bottom-up) menjadi Bahasa Tertentu Domain Tertanam (EDSL) . Ini memungkinkan Anda mengembangkan cara untuk mengungkapkan masalah bisnis Anda dengan cara yang wajar untuk domain Anda dalam bahasa pemrograman. Haskell dan Lisp sama-sama bangga akan hal ini.

Bagian (jika tidak semua) dari apa yang memungkinkan kemampuan ini adalah lebih banyak fleksibilitas dan ekspresi dalam bahasa dasar itu sendiri; dengan fungsi kelas satu, fungsi tingkat tinggi, komposisi fungsi, dan dalam beberapa bahasa, tipe data aljabar (serikat terdiskriminasi AKA) dan kemampuan untuk mendefinisikan operator *, ada lebih banyak fleksibilitas yang tersedia untuk cara mengekspresikan sesuatu daripada yang ada dengan OOP, yang berarti Anda mungkin akan menemukan cara yang lebih alami untuk mengekspresikan sesuatu dari domain masalah Anda. (Seharusnya mengatakan sesuatu yang banyak bahasa OOP telah mengadopsi banyak fitur ini baru-baru ini, jika tidak memulai dengan mereka.)

* Ya, dalam banyak bahasa OOP Anda dapat mengganti operator standar, tetapi di Haskell, Anda dapat menentukan yang baru!

Dalam pengalaman saya bekerja dengan bahasa fungsional (kebanyakan F # dan Haskell, beberapa Clojure, dan sedikit Lisp dan Erlang), saya memiliki waktu yang lebih mudah memetakan ruang masalah ke dalam bahasa daripada yang saya lakukan dengan OOP - terutama dengan tipe data aljabar, yang saya temukan lebih fleksibel daripada kelas. Sesuatu yang mendorong saya untuk mengulang ketika memulai dengan FP, terutama dengan Haskell, adalah bahwa saya harus berpikir / bekerja pada tingkat yang sedikit lebih tinggi daripada yang saya gunakan dalam bahasa imperatif atau OOP; Anda mungkin mengalami sedikit ini juga.

paul
sumber
Masalah bisnis (dari pelanggan) tidak sering diekspresikan dalam fungsi tingkat tinggi. Tetapi pelanggan dapat menulis cerita pengguna satu baris dan memberi Anda aturan bisnis (atau Anda bisa mengeluarkannya dari pelanggan). Saya tertarik dengan pemodelan domain (top-down?) (Dari artefak itu) yang memungkinkan kami untuk sampai pada abstraksi masalah yang dipetakan ke fungsi kelas satu, dll. Bisakah Anda mengutip beberapa referensi? Bisakah Anda menggunakan contoh konkret domain, abstraksi, dll.?
Fuhrmanator
3
@Fuhrmanator Seorang pelanggan masih dapat menulis cerita pengguna satu-baris dan aturan bisnis terlepas dari apakah Anda menggunakan OOP dan FP . Saya tidak berharap pelanggan memahami fungsi tingkat tinggi seperti yang saya harapkan mereka tidak memahami warisan, komposisi, atau antarmuka.
Andres F.
1
@Fuhrmanator Seberapa sering Anda memiliki pelanggan mengungkapkan keprihatinan mereka dalam hal generik Java atau kelas dasar dan antarmuka abstrak? Kepada Tuhan. Paul telah memberi Anda jawaban yang sangat bagus, menjelaskan metode pemodelan yang praktis dan andal menggunakan teknik yang tentunya tidak terlalu sulit untuk divisualisasikan. Namun Anda bersikeras bahwa itu dijelaskan dalam satu teknik pemodelan spesifik untuk satu paradigma tertentu, seolah-olah itu adalah cara yang paling alami untuk mewakili desain dan hal lain dapat digambar ulang dalam istilah-istilahnya.
kuncinya
@Fuhrmanator Ini mungkin tidak setinggi yang Anda cari, tetapi harus memberikan wawasan tentang proses desain menggunakan teknik fungsional: Merancang Dengan Jenis . Saya akan merekomendasikan menjelajah situs itu secara umum karena memiliki beberapa artikel yang bagus.
paul
@Fuhrmanator Ada juga seri Functioning Functionally ini
paul
3

Seperti yang dikatakan Niklaus Wirth, "Algoritma + Struktur Data = Program". Pemrograman fungsional adalah tentang cara mengatur algoritma, dan tidak memberi tahu banyak tentang cara mengatur struktur data. Memang, ada bahasa FP baik dengan variabel bisa berubah (Lisp) dan tidak berubah (Haskell, Erlang). Jika Anda ingin membandingkan dan membedakan FP dengan sesuatu, Anda harus memilih pemrograman imperatif (C, Java) dan deklaratif (Prolog).

OOP di sisi lain adalah cara untuk membangun struktur data dan melampirkan algoritma pada mereka. FP tidak mencegah Anda membangun struktur data yang mirip dengan OOP. Jika Anda tidak mempercayai saya, lihatlah deklarasi tipe Haskell. Namun, sebagian besar bahasa FP setuju bahwa fungsi bukan milik struktur data dan lebih baik berada di namespace yang sama. Ini dilakukan untuk menyederhanakan membangun algoritma baru melalui komposisi fungsi. Memang, jika Anda tahu input apa yang dibutuhkan suatu fungsi dan output apa yang dihasilkannya, mengapa harus mementingkan struktur data yang mana juga? Sebagai contoh, mengapa addfungsi harus dipanggil pada instance tipe Integer dan mengeluarkan argumen alih-alih hanya melewati dua argumen Integer?

Oleh karena itu, saya tidak melihat mengapa FP harus membuat solusi lebih sulit untuk dipahami secara umum, dan saya tidak berpikir itu melakukannya. Namun, perlu diingat bahwa programmer imperatif berpengalaman pasti akan menemukan program fungsional lebih sulit untuk dipahami daripada yang imperatif, dan sebaliknya. Ini mirip dengan dikotomi Windows-Linux ketika orang-orang yang telah berinvestasi 10 tahun untuk merasa nyaman dengan lingkungan Windows menemukan Linux sulit setelah satu bulan penggunaan, dan mereka yang terbiasa dengan Linux tidak dapat mencapai produktivitas yang sama di Windows. Oleh karena itu, 'kesenjangan representasional' yang Anda bicarakan sangat subjektif.

mkalkov
sumber
Karena enkapsulasi dan penyembunyian data, yang bukan prinsip OO sendiri, saya tidak sepenuhnya setuju dengan OO menjadi struktur data + algoritma (itu hanya tampilan internal). Keindahan dari setiap abstraksi yang baik adalah bahwa ada beberapa layanan yang disediakannya untuk menyelesaikan bagian dari masalah, tanpa perlu memahami terlalu banyak detail. Saya pikir Anda berbicara enkapsulasi ketika Anda memisahkan fungsi dan data dalam FP, tapi saya terlalu hijau untuk tahu pasti. Juga, saya mengedit pertanyaan saya untuk merujuk penelusuran dari solusi kembali ke masalah (untuk memperjelas arti kesenjangan representasional).
Fuhrmanator
if you know what input a function takes and what output it produces, why should it matter which data structure it belongs too?Kedengarannya sangat mirip kohesi, yang penting bagi sistem modular. Saya berpendapat bahwa tidak mengetahui di mana menemukan suatu fungsi akan membuat lebih sulit untuk memahami solusi, yang disebabkan oleh kesenjangan representasional yang lebih tinggi. Banyak sistem OO memiliki masalah ini, tetapi itu karena desain yang buruk (kohesi rendah). Sekali lagi, masalah namespace keluar dari keahlian saya di FP, jadi mungkin itu tidak seburuk kedengarannya.
Fuhrmanator
1
@Fuhrmanator Tapi Anda jangan tahu di mana untuk menemukan fungsi. Dan hanya ada satu fungsi, bukan beberapa fungsi dengan nama yang sama, yang ditentukan untuk setiap tipe data (sekali lagi, lihat "Masalah Ekspresi"). Misalnya, untuk fungsi pustaka Haskell (yang Anda disarankan untuk digunakan, alih-alih menemukan kembali roda atau membuat versi yang sedikit kurang berguna dari fungsi-fungsi tersebut), Anda memiliki alat penemuan luar biasa seperti Hoogle , yang begitu kuat sehingga memungkinkan Anda mencari dengan tanda tangan (coba saja :))
Andres F.
1
@Fuhrmanator, setelah "Kedengarannya sangat mirip kohesi", saya akan mengharapkan Anda untuk secara logis menyimpulkan bahwa bahasa FP memungkinkan Anda menulis program dengan kohesi yang lebih tinggi tetapi Anda membuat saya terkejut. :-) Saya pikir Anda harus memilih bahasa FP, mempelajarinya dan memutuskan sendiri. Jika saya jadi Anda, saya sarankan untuk mulai dengan Haskell karena itu cukup murni dan karena itu tidak akan membiarkan Anda menulis kode dengan gaya imperatif. Erlang dan beberapa Lisp juga merupakan pilihan yang baik tetapi mereka bercampur dalam gaya pemrograman lain. Scala dan Clojure, IMO, cukup rumit untuk memulai.
mkalkov