Mengapa Python tidak terlalu bagus untuk pemrograman fungsional? [Tutup]

324

Saya selalu berpikir bahwa pemrograman fungsional dapat dilakukan dengan Python. Jadi, saya terkejut bahwa Python tidak banyak menyebutkan dalam pertanyaan ini , dan ketika disebutkan, biasanya tidak terlalu positif. Namun, tidak banyak alasan diberikan untuk ini (kurangnya pencocokan pola dan tipe data aljabar disebutkan). Jadi pertanyaan saya adalah: mengapa Python tidak bagus untuk pemrograman fungsional? Apakah ada lebih banyak alasan daripada kurangnya pencocokan pola dan tipe data aljabar? Atau apakah konsep-konsep ini begitu penting untuk pemrograman fungsional sehingga bahasa yang tidak mendukungnya hanya dapat digolongkan sebagai bahasa pemrograman fungsional tingkat kedua? (Perlu diingat bahwa pengalaman saya dengan pemrograman fungsional sangat terbatas.)

David Johnstone
sumber
2
2018 - Coconut (bahasa pemrograman fungsional yang mengkompilasi ke Python) meningkatkan pemrograman fungsional dalam Python. Lihat juga seri artikel ini dari IBM page1 page2 page3
cssyphus

Jawaban:

393

Pertanyaan yang Anda referensi menanyakan bahasa mana yang mempromosikan OO dan pemrograman fungsional. Python tidak mempromosikan pemrograman fungsional walaupun ia bekerja dengan cukup baik.

Argumen terbaik melawan pemrograman fungsional dalam Python adalah bahwa kasus penggunaan imperatif / OO secara hati-hati dipertimbangkan oleh Guido, sementara case penggunaan pemrograman fungsional tidak. Ketika saya menulis Python imperatif, itu adalah salah satu bahasa tercantik yang saya tahu. Ketika saya menulis Python fungsional, itu menjadi jelek dan tidak menyenangkan seperti bahasa rata-rata Anda yang tidak memiliki BDFL .

Yang tidak berarti itu buruk, hanya saja Anda harus bekerja lebih keras daripada yang Anda lakukan jika Anda beralih ke bahasa yang mempromosikan pemrograman fungsional atau beralih ke penulisan OO Python.

Berikut ini hal-hal fungsional yang saya lewatkan di Python:


  • Tanpa pencocokan pola dan tanpa rekursi ekor berarti algoritma dasar Anda harus ditulis secara imperatif. Rekursi jelek dan lambat dalam Python.
  • Perpustakaan daftar kecil dan tidak ada kamus fungsional berarti Anda harus menulis banyak hal sendiri.
  • Tidak ada sintaks untuk currying atau komposisi yang berarti bahwa gaya point-free hampir penuh dengan tanda baca sama seperti melewati argumen secara eksplisit.
  • Iterator bukan daftar malas berarti bahwa Anda harus tahu apakah Anda ingin efisiensi atau ketekunan, dan untuk menyebarkan panggilan ke list sekitar jika Anda ingin kegigihan. (Iterator digunakan sekali)
  • Sintaks imperatif sederhana Python, bersama dengan pengurai LL1 sederhana, berarti bahwa sintaksis yang lebih baik untuk ekspresi if dan ekspresi lambda pada dasarnya tidak mungkin. Guido menyukainya dengan cara ini, dan saya pikir dia benar.
Nathan Shively-Sanders
sumber
5
+1 untuk rekursi ekor yang hilang - meskipun konstruksi perulangan telah menggantikannya, masih ada sesuatu yang hilang antara Python dan Skema.
new123456
5
Jawaban sempurna untuk kelengkapan dan komposisi. Sayangnya, seperti dengan begitu banyak jawaban dengan latar belakang fungsional yang kuat, IMO menggunakan terminologi yang kasar. Sementara saya mengerti bahwa Anda tidak dapat menguraikan setiap konsep dalam sebuah jawaban, saya bertanya-tanya apakah OP (dengan latar belakang FP yang diakui terbatas) mendapat informasi dengan baik ketika membaca istilah seperti "pencocokan pola", "kamus fungsional", "currying", atau " daftar malas ".
ThomasH
4
Poin bagus; Saya pikir solusinya adalah menambahkan tautan. Apakah Anda memiliki cukup perwakilan untuk mengedit jawaban saya? Jika demikian silakan menambahkan tautan ke berbagai konsep. Saya akan mulai ketika saya punya waktu nanti.
Nathan Shively-Sanders
5
Saya menyadari ini berusia 5 tahun, tapi ... ini sepertinya lebih tentang hal-hal yang Anda lewatkan dari Haskell , bukan dari bahasa fungsional . Misalnya, sebagian besar dialek dan keturunan ML dan Lisp tidak memiliki currying otomatis, membuat gaya point-free terlalu bertele-tele, tidak memiliki daftar malas, dll. Jadi, jika iterator bukannya daftar malas menjadikan Python bahasa fungsional yang buruk, memiliki tidak juga harus membuat CaML bahasa fungsional yang mengerikan ?
abarnert
4
@abarnert: Caml memiliki setiap poin kecuali daftar malas, yang tersedia sebagai perpustakaan. Saya sesekali menggunakan Caml pada saat saya menulis jawaban ini dan saat ini menggunakan F #. Keduanya bahasa fungsional yang sangat bagus.
Nathan Shively-Sanders
102

Guido punya penjelasan bagus tentang ini di sini . Inilah bagian yang paling relevan:

Saya tidak pernah menganggap Python sangat dipengaruhi oleh bahasa fungsional, tidak peduli apa yang orang katakan atau pikirkan. Saya jauh lebih akrab dengan bahasa imperatif seperti C dan Algol 68 dan meskipun saya telah membuat fungsi objek kelas satu, saya tidak melihat Python sebagai bahasa pemrograman fungsional. Namun, sebelumnya, jelas bahwa pengguna ingin berbuat lebih banyak dengan daftar dan fungsi.

...

Perlu juga dicatat bahwa meskipun saya tidak membayangkan Python sebagai bahasa fungsional, pengenalan penutupan telah berguna dalam pengembangan banyak fitur pemrograman canggih lainnya. Misalnya, aspek tertentu dari kelas gaya baru, dekorator, dan fitur modern lainnya bergantung pada kemampuan ini.

Terakhir, meskipun sejumlah fitur pemrograman fungsional telah diperkenalkan selama bertahun-tahun, Python masih kekurangan fitur tertentu yang ditemukan dalam bahasa pemrograman fungsional "nyata". Misalnya, Python tidak melakukan beberapa jenis optimasi (misalnya, rekursi ekor). Secara umum, karena sifat Python yang sangat dinamis, mustahil untuk melakukan optimasi waktu kompilasi yang dikenal dari bahasa fungsional seperti Haskell atau ML. Dan itu tidak masalah.

Saya menarik dua hal dari ini:

  1. Pembuat bahasa tidak benar-benar menganggap Python sebagai bahasa fungsional. Oleh karena itu, dimungkinkan untuk melihat fitur "fungsional-esque", tetapi Anda tidak mungkin melihat apa pun yang secara fungsional fungsional.
  2. Sifat dinamis Python menghambat beberapa optimasi yang Anda lihat dalam bahasa fungsional lainnya. Memang, Lisp sama dinamis (jika tidak lebih dinamis) seperti Python, jadi ini hanya penjelasan parsial.
Jason Baker
sumber
8
Anda dapat melakukan optimasi panggilan ekor dengan Python. Guido tidak / tidak mengerti itu.
Jules
26
Tampaknya bermuara pada gaya fungsional yang Guido van Rossum tidak suka .
Svante
59
Saya pikir itu lebih akurat untuk mengatakan bahwa Guido van Rossum tidak mengerti gaya fungsional, dan tidak mengerti mengapa Python membutuhkannya. Anda harus memahami dua hal: 1) bahasa pemrograman berada di bagian bawah tumpukan teknologi dan memengaruhi segala sesuatu yang dibangun di atasnya dan 2) sama seperti perangkat lunak lainnya, lebih mudah untuk menambahkan fitur daripada menghapusnya. Jadi saya pikir itu adalah kualitas yang baik bagi seorang perancang bahasa untuk bersikap kritis terhadap permintaan semacam ini.
Jason Baker
8
"Memang, Lisp sama dinamisnya" -> dan sama pentingnya!
pyon
6
@ Jules, apakah Anda keberatan berbagi pedoman untuk penggunaan optimasi panggilan ekor di Python? Pointer ke beberapa sumber akan bermanfaat.
David Shaked
52

Skema tidak memiliki tipe data aljabar atau pencocokan pola tetapi itu jelas merupakan bahasa fungsional. Mengganggu hal-hal tentang Python dari perspektif pemrograman fungsional:

  1. Lambdas yang lumpuh. Karena Lambdas hanya dapat berisi ekspresi, dan Anda tidak dapat melakukan semuanya dengan mudah dalam konteks ekspresi, ini berarti bahwa fungsi yang dapat Anda tetapkan "on the fly" terbatas.

  2. Jika adalah pernyataan, bukan ekspresi. Ini berarti, antara lain, Anda tidak dapat memiliki lambda dengan If di dalamnya. (Ini diperbaiki oleh terner di Python 2.5, tetapi terlihat jelek.)

  3. Guido mengancam untuk menghapus peta, memfilter, dan mengurangi sesekali

Di sisi lain, python memiliki penutup leksikal, Lambdas, dan daftar pemahaman (yang benar-benar konsep "fungsional" apakah Guido mengakuinya atau tidak). Saya melakukan banyak pemrograman "fungsional-style" dengan Python, tapi saya hampir tidak mengatakan itu ideal.

Yakub B
sumber
3
Memetakan, memfilter, dan mengurangi benar-benar tidak diperlukan dengan python. Saya belum melihat sepotong kode yang sangat disederhanakan dengan menggunakannya. Plus, memanggil fungsi-fungsi dalam Python bisa jadi mahal, jadi biasanya lebih baik hanya menggunakan daftar / generator pemahaman atau untuk loop saja.
Jason Baker
2
Inilah yang dikatakan Nathan Sanders di bawah ini: "Python tidak mempromosikan pemrograman fungsional meskipun ia bekerja dengan cukup baik." Jika Guido ingin Python menjadi bahasa fungsional, ia akan membuat implementasinya bekerja cukup baik untuk menggunakan fungsi throwaway, dan akan menguraikan Lambdas sejauh Anda benar-benar dapat menggunakan peta / filter / kurangi dengan cara yang bermanfaat. Di sisi lain, orang-orang fungsional mulai bangun dengan kehebatan pemahaman daftar. Semoga kita tidak harus memilih yang satu atau yang lain.
Jacob B
7
peta dan filter secara sepele diganti dengan pemahaman daftar. mengurangi - hampir selalu - sangat tidak efisien sehingga harus diganti dengan fungsi generator.
S.Lott
13
@ S.Lott, bagaimana Anda menggantinya dengan generator?
Antimony
17
@JacobB Daftar pemahaman tersedia dalam bahasa fungsional sekitar 15 tahun sebelum Python ditemukan dan 25 tahun sebelum Python memperoleh implementasi fitur. Gagasan bahwa Python telah mempengaruhi penyebarannya, atau bahwa fp mempelajari ini dari Python, atau bahkan sekadar bahwa popularitasnya di dunia fp pasca-tanggal implementasi Python, adalah salah. Implementasi Python diambil langsung dari Haskell. Mungkin saya telah salah paham tentang Anda dan bukan itu yang Anda maksudkan, tetapi saya bingung oleh "orang-orang fungsional mulai bangun dengan kehebatan pemahaman daftar".
bruce
23

Saya tidak akan pernah menyebut Python "fungsional" tetapi setiap kali saya memprogram di Python kode selalu berakhir menjadi hampir sepenuhnya fungsional.

Memang, itu terutama karena pemahaman daftar yang sangat bagus. Jadi saya tidak perlu menyarankan Python sebagai bahasa pemrograman fungsional tapi saya akan menyarankan pemrograman fungsional untuk siapa pun yang menggunakan Python.

Konrad Rudolph
sumber
17

Biarkan saya menunjukkan dengan sepotong kode yang diambil dari jawaban pertanyaan Python "fungsional" pada SO

Python:

def grandKids(generation, kidsFunc, val):
  layer = [val]
  for i in xrange(generation):
    layer = itertools.chain.from_iterable(itertools.imap(kidsFunc, layer))
  return layer

Haskell:

grandKids generation kidsFunc val =
  iterate (concatMap kidsFunc) [val] !! generation

Perbedaan utama di sini adalah bahwa perpustakaan standar Haskell memiliki fungsi yang berguna untuk pemrograman fungsional: dalam hal ini iterate, concatdan(!!)

yairchu
sumber
7
Berikut pengganti satu baris untuk grandKids()tubuh dengan ekspresi Generator: return reduce(lambda a, v: concat((x for x in kidsFunc(v)) for v in a), xrange(generation), [val]).
Lloeki
6
Dan inilah salah satu yang tidak perlu concat:return reduce(lambda a, v: (x for v in a for x in kidsFunc(v)), xrange(generation), [val])
Lloeki
9
@Lloeki: iterate akan menyederhanakan kode itu secara signifikan, dan (x untuk v dalam untuk x di kidsFunc (v)) jauh lebih jelas sebagai concatMap (kidsFunc). Kurangnya builtin tingkat tinggi bagus Python membuat kode setara cryptic dan verbose dibandingkan dengan Haskell.
Phob
2
concat dapat digantikan olehitertools.chain.from_iterable
Antimony
@Antimony: baik untuk tahu. thx
yairchu
14

Satu hal yang sangat penting untuk pertanyaan ini (dan jawabannya) adalah sebagai berikut: Apa sih pemrograman fungsional, dan apa sifat paling penting dari itu. Saya akan mencoba memberikan pandangan saya tentang itu:

Pemrograman fungsional sangat mirip menulis matematika di papan tulis. Saat Anda menulis persamaan di papan tulis, Anda tidak memikirkan perintah eksekusi. Tidak ada mutasi. Anda tidak kembali pada hari berikutnya dan melihatnya, dan ketika Anda membuat perhitungan lagi, Anda mendapatkan hasil yang berbeda (atau Anda mungkin, jika Anda memiliki kopi segar :)). Pada dasarnya, apa yang ada di papan tulis ada di sana, dan jawabannya sudah ada di sana ketika Anda mulai menuliskan sesuatu, Anda belum menyadari apa itu.

Pemrograman fungsional banyak seperti itu; Anda tidak mengubah banyak hal, Anda hanya mengevaluasi persamaan (atau dalam hal ini, "program") dan mencari tahu apa jawabannya. Program itu masih ada, tidak dimodifikasi. Sama dengan data.

Saya akan memberi peringkat berikut sebagai fitur paling penting dari pemrograman fungsional: a) transparansi referensial - jika Anda mengevaluasi pernyataan yang sama di waktu dan tempat lain, tetapi dengan nilai variabel yang sama, itu tetap berarti sama. b) tidak ada efek samping - tidak peduli berapa lama Anda menatap papan tulis, persamaan yang dilihat orang lain dengan papan tulis lain tidak akan berubah secara tidak sengaja. c) fungsi adalah nilai juga. yang dapat diteruskan dan diterapkan dengan, atau ke, variabel lain. d) komposisi fungsi, Anda dapat melakukan h = g · f dan dengan demikian mendefinisikan fungsi baru h (..) yang setara dengan memanggil g (f (..)).

Daftar ini dalam urutan prioritas saya, jadi transparansi referensial adalah yang paling penting, diikuti tanpa efek samping.

Sekarang, jika Anda membaca python dan memeriksa seberapa baik bahasa dan perpustakaan mendukung, dan menjamin, aspek-aspek ini - maka Anda berada di jalan yang baik untuk menjawab pertanyaan Anda sendiri.

xeno
sumber
2
Fungsinya adalah kelas satu dalam Python.
Carl Smith
@CarlSmith Yang itu, tapi menyisakan 3/4 yang tidak dimiliki Python. : - \
arya
1
Saya tidak berpikir Python adalah bahasa yang baik untuk pemrograman fungsional. Saya bahkan tidak yakin sekarang apa yang saya maksud dengan komentar itu jujur. Tampaknya tidak relevan dengan jawabannya. Saya akan menghapusnya, tetapi komentar Anda akan keluar dari konteks.
Carl Smith
1
Transparansi referensial dan kekekalan bukan fitur bahasa sebenarnya. Ya, beberapa bahasa (Haskell) menekankan mereka dan membuatnya sulit untuk tidak memilikinya, tetapi Anda dapat membuat fungsi yang secara transparan transparan atau objek yang tidak berubah dalam dasarnya bahasa apa pun. Anda hanya perlu bekerja di sekitar perpustakaan standar, yang akan sering melanggar mereka.
Kevin
Juga, Python memiliki dukungan untuk kari dan komposisi, tetapi tidak pada tingkat bahasa, itu ada di perpustakaan standar sebagai gantinya.
Kevin
10

Python hampir merupakan bahasa fungsional. Ini "fungsional lite".

Ini memiliki fitur tambahan, jadi itu tidak cukup murni untuk beberapa orang.

Itu juga tidak memiliki beberapa fitur, jadi itu tidak cukup lengkap untuk beberapa.

Fitur yang hilang relatif mudah untuk ditulis. Lihat pos seperti ini di FP dengan Python.

S.Lott
sumber
2
Sebagian besar, saya setuju dengan posting ini. Tapi saya tidak setuju dengan mengatakan bahwa Python adalah bahasa fungsional. Ini sangat mendorong pemrograman imperatif, dan sulit untuk tidak menggunakan "fitur tambahan" yang Anda sebutkan. Saya pikir yang terbaik untuk merujuk ke Python sebagai "lite fungsional" seperti yang Anda lakukan di posting lain. :-)
Jason Baker
8
-1 Maaf, tidak. Maksudku, hanya, tidak. Bahasa fungsional menyediakan konstruksi yang memfasilitasi penalaran formal: induktif (ML), persamaan (Haskell). Penutupan dan fungsi anonim saja hanyalah gula sintaksis untuk pola strategi.
pyon
8

Alasan lain yang tidak disebutkan di atas adalah bahwa banyak fungsi built-in dan metode tipe built-in memodifikasi objek tetapi tidak mengembalikan objek yang dimodifikasi. Jika objek yang diubah dikembalikan, itu akan membuat kode fungsional lebih bersih dan lebih ringkas. Misalnya, jika some_list.append (some_object) mengembalikan some_list dengan some_object ditambahkan.

Dvd Avins
sumber
4

Selain jawaban lain, satu alasan Python dan sebagian besar bahasa multi-paradigma lainnya tidak cocok untuk pemrograman fungsional yang sebenarnya adalah karena kompiler / mesin virtual / run-times mereka tidak mendukung optimasi fungsional. Optimalisasi semacam ini dicapai oleh kompiler yang memahami aturan matematika. Sebagai contoh, banyak bahasa pemrograman mendukung mapfungsi atau metode. Ini adalah fungsi yang cukup standar yang mengambil fungsi sebagai satu argumen dan iterable sebagai argumen kedua kemudian menerapkan fungsi itu untuk setiap elemen di iterable.

Bagaimanapun ternyata itu map( foo() , x ) * map( foo(), y )sama dengan map( foo(), x * y ). Kasus terakhir sebenarnya lebih cepat dari yang pertama karena yang pertama melakukan dua salinan di mana yang terakhir melakukan satu.

Bahasa fungsional yang lebih baik mengenali hubungan berbasis matematis ini dan secara otomatis melakukan optimasi. Bahasa yang tidak didedikasikan untuk paradigma fungsional kemungkinan tidak akan optimal.


sumber
map( foo() , x ) * map( foo(), y ) == map( foo(), x * y )tidak benar untuk semua fungsi. Sebagai contoh, pertimbangkan kasing ketika foomenghitung turunan.
Eli Korvigo
1
Saya pikir maksudnya +alih-alih *.
user1747134
Anda menganggap foo () linier?
juan Isaza
properti itu TIDAK benar untuk foo (x) = x + 1. As (x + 1) * (y + 1)! = X * y + 1.
juan Isaza