Apakah sejumlah kecil pemrograman fungsional dapat dipahami oleh orang-orang non-FP? [Tutup]

43

Kasus : Saya bekerja di sebuah perusahaan, menulis aplikasi dengan Python yang menangani banyak data dalam array. Saya satu-satunya pengembang program ini saat ini, tetapi mungkin akan digunakan / dimodifikasi / diperpanjang di masa depan (1-3 tahun) oleh beberapa programmer lain, pada saat ini tidak saya kenal. Saya mungkin tidak akan ada di sana secara langsung untuk membantu, tetapi mungkin memberikan dukungan melalui email jika saya punya waktu untuk itu.

Jadi, sebagai pengembang yang telah mempelajari pemrograman fungsional (Haskell), saya cenderung menyelesaikan, misalnya, memfilter seperti ini:

filtered = filter(lambda item: included(item.time, dur), measures)

Sisa kode adalah OO, hanya beberapa kasus kecil di mana saya ingin menyelesaikannya seperti ini, karena jauh lebih sederhana dan lebih indah menurut saya.

Pertanyaan : Apakah boleh hari ini menulis kode seperti ini?

  • Bagaimana pengembang yang belum menulis / mempelajari FP bereaksi terhadap kode seperti ini?
  • Apakah bisa dibaca?
  • Dapat dimodifikasi?
  • Haruskah saya menulis dokumentasi seperti menjelaskan kepada seorang anak apa garis itu?

     # Filter out the items from measures for which included(item.time, dur) != True

Saya telah bertanya kepada bos saya, dan dia hanya mengatakan "FP adalah ilmu hitam, tetapi jika itu berhasil dan merupakan solusi yang paling efisien, maka boleh saja menggunakannya."

Apa pendapat Anda tentang ini? Sebagai programmer non-FP, bagaimana Anda bereaksi terhadap kode? Apakah kode itu "googable" sehingga Anda dapat mengerti apa fungsinya? Saya ingin umpan balik tentang ini.

kd35a
sumber
14
Menurut pendapat saya banyak bahasa modern memungkinkan beberapa tingkat pemrograman fungsional dan penggunaannya menjadi semakin umum. Secara pribadi saya akan mengatakan pergi untuk itu (setidaknya untuk tugas penyaringan / pemetaan yang relatif sederhana).
Joachim Sauer
Saya tidak bisa memberikan jawaban yang tidak terpengaruh, karena saya suka FP. Ini akan menjadi ide yang baik untuk menambahkan komentar, jika itu tidak sederhana.
Bruno Schäpper
3
Komentar Anda bisa lebih jelas; filter menyertakan elemen yang pengujiannya Benar, sehingga komentar Anda dapat membaca # Select the item's from measures for which included(item.time, dur) == True:, menghindari negatif ganda selalu meningkatkan pemahaman.
Martijn Pieters
6
Sudahkah Anda mempertimbangkan untuk menggunakan pemahaman daftar? Mereka sering dianggap lebih "pythonic" daripada peta / filter.
phant0m
2
@MatjazMuhic Nah, itu indah ...;)
kd35a

Jawaban:

50

Apakah bisa dibaca?

Bagi saya: Ya, tetapi saya mulai mengerti, bahwa komunitas Python sering menganggap daftar pemahaman sebagai solusi yang lebih bersih daripada menggunakan map()/ filter().

Bahkan, GvR bahkan mempertimbangkan untuk menjatuhkan fungsi-fungsi itu sama sekali.

Pertimbangkan ini:

filtered = [item for item in measures if included(item.time, dur)]

Lebih lanjut, ini memiliki manfaat bahwa pemahaman daftar akan selalu mengembalikan daftar. map()dan filter()di sisi lain akan mengembalikan iterator dengan Python 3.

Catatan: Jika Anda ingin memiliki iterator, gantinya sesederhana mengganti []dengan ():

filtered = (item for item in measures if included(item.time, dur))

Sejujurnya, saya melihat sedikit atau tidak ada alasan untuk menggunakan map()atau filter()dengan Python.

Apakah bisa dimodifikasi?

Ya, tentu saja, ada satu hal untuk membuatnya lebih mudah: Jadikan fungsi, bukan lambda.

def is_included(item):
    return included(item.time, dur)
filtered = filter(is_included, measures)
filtered = [item for item in measures if is_included(item)]

Jika kondisi Anda menjadi lebih kompleks, skala ini akan jauh lebih mudah, memungkinkan Anda untuk menggunakan kembali cek Anda. (Perhatikan bahwa Anda dapat membuat fungsi di dalam fungsi lain, ini dapat membuatnya lebih dekat ke tempat di mana ia digunakan.)

Bagaimana seorang pengembang yang belum menulis / belajar FP bereaksi pada kode seperti ini?

Dia mencari dokumentasi Python dan tahu cara kerjanya lima menit kemudian. Kalau tidak, dia seharusnya tidak pemrograman dengan Python.

map()dan filter()yang sangat sederhana. Bukannya Anda meminta mereka untuk memahami monad. Itu sebabnya saya pikir Anda tidak perlu menulis komentar seperti itu. Gunakan nama variabel dan fungsi yang baik, maka kodenya hampir jelas. Anda tidak dapat mengantisipasi fitur bahasa mana yang tidak diketahui pengembang. Sejauh yang Anda tahu, pengembang berikutnya mungkin tidak tahu apa itu kamus.

Apa yang tidak kita mengerti biasanya tidak dapat dibaca oleh kita. Dengan demikian, Anda bisa berargumen itu tidak lebih mudah dibaca daripada pemahaman daftar jika Anda belum pernah melihat salah satu dari mereka sebelumnya. Tetapi seperti yang disebutkan Joshua dalam komentarnya, saya juga percaya bahwa penting untuk konsisten dengan apa yang digunakan pengembang lain - setidaknya jika alternatifnya tidak memberikan keuntungan substansial.

hantu0m
sumber
5
Mungkin layak juga menyebutkan ekspresi generator , yang bekerja sama dengan pemahaman daftar tetapi mengembalikan generator alih-alih daftar, seperti mapdan filterlakukan dengan python 3.
James
@ James: Ide bagus, saya telah menambahkannya ke posting saya. Terima kasih!
phant0m
2
Saya biasanya memunculkan reducesebagai contoh tandingan untuk Anda selalu dapat menggunakan argumen pemahaman daftar , karena relatif sulit untuk diganti reducedengan generator inline atau daftar pemahaman.
kojiro
4
+1 untuk mencatat idiom pilihan bahasa yang bersangkutan. Konsistensi IMHO memiliki nilai yang luar biasa dan menggunakan bahasa sedemikian rupa sehingga sebagian besar "speaker" dapat memberikan lebih banyak rawatan daripada komentar pada waktu-waktu tertentu.
Joshua Drake
4
+1 untuk "Dia googles untuk dokumentasi Python dan tahu cara kerjanya lima menit kemudian. Kalau tidak, dia seharusnya tidak pemrograman dengan Python."
Bjarke Freund-Hansen
25

Karena komunitas pengembang mendapatkan kembali minat dalam pemrograman fungsional, tidak jarang melihat beberapa pemrograman fungsional dalam bahasa yang awalnya sepenuhnya berorientasi objek. Contoh yang baik adalah C #, di mana tipe anonim dan ekspresi lambda memungkinkan untuk menjadi lebih pendek dan ekspresif melalui pemrograman fungsional.

Ini dikatakan, pemrograman fungsional aneh untuk pemula. Sebagai contoh, ketika selama kursus pelatihan, saya menjelaskan kepada para pemula bagaimana mereka dapat meningkatkan kode mereka melalui pemrograman fungsional dalam C #, beberapa dari mereka tidak yakin, dan beberapa mengatakan bahwa kode asli lebih mudah dimengerti untuk mereka. Contoh yang saya berikan kepada mereka adalah sebagai berikut:

Kode sebelum refactoring:

var categorizedProducts = new Dictionary<string, List<Product>>();

// Get only enabled products, filtering the disabled ones, and group them by categories.
foreach (var product in this.Data.Products)
{
    if (product.IsEnabled)
    {
        if (!categorizedProducts.ContainsKey(product.Category))
        {
            // The category is missing. Create one.
            categorizedProducts.Add(product.Category, new List<Product>());
        }

        categorizedProducts[product.Category].Add(product);
    }
}

// Walk through the categories.
foreach (var productsInCategory in categorizedProducts)
{
    var minimumPrice = double.MaxValue;
    var maximumPrice = double.MinValue;

    // Walk through the products in a category to search for the maximum and minimum prices.
    foreach (var product in productsInCategory.Value)
    {
        if (product.Price < minimumPrice)
        {
            minimumPrice = product.Price;
        }

        if (product.Price > maximumPrice)
        {
            maximumPrice = product.Price;
        }
    }

    yield return new PricesPerCategory(category: productsInCategory.Key, minimum: minimumPrice, maximum: maximumPrice);
}

Kode yang sama setelah refactoring dengan menggunakan FP:

return this.Data.Products
    .Where(product => product.IsEnabled)
    .GroupBy(product => product.Category)
    .Select(productsInCategory => new PricesPerCategory(
              category: productsInCategory.Key, 
              minimum:  productsInCategory.Value.Min(product => product.Price), 
              maximum:  productsInCategory.Value.Max(product => product.Price))
    );

Ini membuat saya berpikir bahwa:

  • Anda tidak perlu khawatir jika Anda tahu bahwa pengembang berikutnya yang akan menjaga kode Anda akan memiliki pengalaman keseluruhan yang cukup dan beberapa pengetahuan tentang pemrograman fungsional, tetapi:

  • jika tidak, hindari pemrograman fungsional, atau berikan komentar verbose yang menjelaskan sintaksis, kelebihan, dan kemungkinan peringatan dari pendekatan Anda pada saat yang bersamaan dibandingkan dengan pemrograman non-fungsional.

Arseni Mourzenko
sumber
8
+1 jika FP tidak membuat kode Anda lebih mudah dibaca oleh siapa pun , Anda salah melakukannya.
György Andrasek
7
Saya dapat melihat bagaimana secara terpisah seseorang yang tidak pernah melihat FP sebelumnya dapat menganggap potongan sebelumnya lebih mudah dibaca daripada yang terakhir. Tetapi bagaimana jika kita mengalikan ini dengan 100? Membaca 100 kalimat singkat yang hampir mirip dengan bahasa Inggris yang menggambarkan apa vs ribuan baris yang menyambungkan kode cara . Volume kode yang murni, betapapun akrabnya, seharusnya begitu luar biasa sehingga keakraban bukanlah kemenangan besar lagi. Pada titik tertentu pasti lebih mudah bagi siapa saja untuk merasa nyaman dengan elemen-elemen FP dan kemudian membaca beberapa baris vs membaca ribuan baris kode yang sudah dikenal.
Esailija
7
Yang paling menggangguku adalah bahwa kita puas percaya bahwa pengembang tidak boleh belajar gaya fungsional. Keuntungan telah terbukti berkali-kali, paradigma ini didukung oleh bahasa umum. Jika orang tidak memiliki kemampuan untuk memahami teknik fungsional, mereka harus diajari atau harus mengajar diri mereka sendiri, bahkan jika mereka tidak bermaksud menggunakannya. Saya benci XSLT dengan hasrat yang membara, tetapi itu tidak menghentikan saya untuk mempelajarinya, sebagai seorang profesional.
Sprague
2
@ UtamaMa Poin Anda sepenuhnya valid, saya seharusnya lebih spesifik. Yang saya maksudkan adalah bahwa pengembang dalam bahasa apa pun harus diharapkan untuk menggunakan fitur-fitur bahasa tersebut secara efektif. Misalnya, menggunakan 'gaya fungsional' dalam C # (menggunakan filter / peta / mengurangi gaya pemrograman, atau fungsi lewat / kembali) bukanlah hal yang baru, dan jadi saya pikir setiap pengembang C # yang tidak mampu membaca pernyataan seperti itu harus memperbarui mereka keterampilan ... mungkin sangat cepat. Saya tentu berpikir setiap pengembang harus belajar sedikit Haskell, tetapi hanya untuk alasan akademis. Ini hal yang berbeda.
Sprague
2
@Sprague: Saya mengerti maksud Anda dan setuju. Hanya saja kita hampir tidak bisa mengharapkan misalnya programmer C # mulai menggunakan paradigma dari FP, ketika terlalu banyak dari programmer itu bahkan tidak menggunakan obat generik. Sampai ada begitu banyak programmer yang tidak terampil, standar profesi kita akan rendah, terutama karena kebanyakan orang tanpa latar belakang teknis tidak mengerti sama sekali tentang pengembangan.
Arseni Mourzenko
20

Saya seorang programmer non-FP dan baru-baru ini saya memodifikasi kode kolega saya dalam JavaScript. Ada permintaan-Http dengan panggilan balik yang sangat mirip dengan pernyataan yang disertakan oleh Anda. Saya harus mengatakan bahwa saya butuh waktu (seperti setengah jam) untuk menyelesaikannya (kode semuanya tidak terlalu besar).

Tidak ada komentar, dan saya pikir tidak ada keharusan untuk itu. Saya bahkan tidak meminta kolega saya untuk membantu saya memahami kodenya.

Dengan mempertimbangkan bahwa saya bekerja selama sekitar 1,5 tahun, saya pikir sebagian besar programmer akan dapat memahami dan memodifikasi kode seperti itu, sejak saya melakukannya.

Selain itu, seperti yang dikatakan Joachim Sauer dalam komentarnya, sering ada potongan-potongan FP dalam banyak bahasa, seperti C # (indexOf, misalnya). Begitu banyak programmer non-FP menangani hal ini cukup sering, dan potongan kode yang Anda masukkan bukanlah sesuatu yang mengerikan atau tidak dapat dipahami.

superM
sumber
1
Terima kasih atas komentar Anda! Ini memberi saya lebih banyak informasi tentang perspektif lain. Sangat mudah untuk menjadi rumah-buta, dan kemudian Anda tidak tahu bagaimana itu tampak seperti ketika Anda tidak tahu FP :)
kd35a
1
@ kd35a, sama-sama Untungnya, saya bisa objektif di sini))
superM
1
+1 untuk menunjukkan bahwa banyak bahasa sekarang mengandung elemen FP.
Joshua Drake
LINQ adalah contoh utama dari FP dalam C #
Konrad Morawski
3

Saya akan mengatakan ya!

Ada banyak aspek pemrograman fungsional, dan menggunakan fungsi tingkat tinggi, seperti dalam contoh Anda, hanya salah satunya.

Sebagai contoh, saya menganggap menulis fungsi murni menjadi sangat penting untuk setiap perangkat lunak yang ditulis dalam bahasa apa pun (di mana "murni" maksud saya tidak ada efek samping), karena:

  • mereka lebih mudah untuk unit test
  • mereka jauh lebih mudah dikomposisikan daripada fungsi efek samping
  • mereka lebih mudah di-debug

Saya juga sering menghindari mutasi nilai dan variabel - konsep lain yang dipinjam dari FP.

Kedua teknik ini berfungsi dengan baik dalam Python dan bahasa lain yang umumnya tidak diklasifikasikan sebagai fungsional. Mereka bahkan sering didukung oleh bahasa itu sendiri (yaitu finalvariabel di Jawa). Dengan demikian, programmer pemeliharaan di masa depan tidak akan menghadapi hambatan besar untuk memahami kode.


sumber
2

Kami melakukan diskusi yang sama tentang perusahaan tempat saya bekerja tahun lalu.

Diskusi tersebut membahas "kode magis" dan apakah itu didorong atau tidak. Ketika melihat lebih dalam lagi, tampaknya orang memiliki pandangan yang sangat berbeda tentang apa yang sebenarnya merupakan "kode magis". Orang-orang yang mengemukakan diskusi tampaknya sebagian besar berarti bahwa ekspresi (dalam PHP) yang menggunakan gaya fungsional adalah "kode magis" sedangkan pengembang yang berasal dari bahasa lain yang menggunakan lebih banyak gaya FP dalam kode mereka tampaknya berpikir bahwa kode magis agak ketika Anda membuat inklusi dinamis file melalui nama file dan sebagainya.

Kami tidak pernah sampai pada kesimpulan yang bagus tentang hal ini, lebih dari itu kebanyakan orang berpikir kode yang terlihat asing adalah "ajaib" atau sulit dibaca. Jadi, apakah itu ide yang baik untuk menghindari kode yang tampaknya asing bagi pengguna lain? Saya pikir itu tergantung di mana ia digunakan. Saya akan menahan diri dari menggunakan ekspresi fp-style (inklusi file dinamis dan sebagainya) dalam metode utama (atau bagian sentral penting dari aplikasi) di mana data harus berupa terowongan dengan cara yang jelas dan mudah dibaca, intuitif, cara. Di sisi lain, saya tidak berpikir seseorang harus takut untuk mendorong amplop, pengembang lain mungkin akan belajar FP dengan cepat jika mereka dihadapkan dengan kode FP dan mungkin memiliki sumber daya yang baik di rumah untuk berkonsultasi tentang masalah tersebut.

TL; DR: Hindari di bagian tengah aplikasi tingkat tinggi (yang perlu dibaca untuk tinjauan umum fungsionalitas aplikasi). Kalau tidak gunakan itu.

Christopher Käck
sumber
Poin bagus dalam menghindari menggunakannya dalam kode tingkat yang lebih tinggi!
kd35a
Saya selalu berpikir ada kekurangan formalisme, dan sangat banyak peluang, dalam mendefinisikan teknik pemrograman dalam berbagai jenis blok (seperti metode statis, metode publik, konstruktor, dll.) Jawaban yang bagus ... itu membuat saya mengunjungi kembali beberapa pikiran-pikiran itu.
Sprague
2

Komunitas C ++ baru-baru ini mendapatkan lambda juga, dan saya percaya mereka memiliki pertanyaan yang kira-kira sama. Namun, jawabannya mungkin tidak sama. Setara dengan C ++ adalah:

std::copy_if(measures.begin(), measures.end(), inserter(filter),
  [dur](Item i) { return included(i, dur) } );

Sekarang std::copybukan hal baru, dan _ifvariasinya juga tidak baru, tetapi lambda adalah. Namun itu didefinisikan dengan cukup jelas dalam konteks: durditangkap dan karenanya konstan, Item ibervariasi dalam loop, dan returnpernyataan tunggal melakukan semua pekerjaan.

Ini terlihat dapat diterima oleh banyak pengembang C ++. Saya belum mencicipi pendapat tentang lambda tingkat tinggi, dan saya berharap penerimaan jauh lebih sedikit.

MSalters
sumber
Poin yang menarik, bahwa ada jawaban yang berbeda tergantung pada bahasa yang digunakan. Mungkin terkait dengan @Christopher Käck memposting tentang bagaimana PHP-coders memiliki lebih banyak masalah dengan hal-hal semacam ini daripada Python-coders.
kd35a
0

Posting potongan kode ke sesama dev yang tidak lancar menggunakan python, dan tanyakan padanya apakah dia bisa menghabiskan 5 menit memeriksa kode untuk melihat apakah dia memahaminya.

Jika ya, Anda mungkin baik untuk pergi. Jika tidak, Anda harus membuatnya lebih jelas.

Bisakah kolega Anda menjadi bodoh dan tidak mengerti sesuatu yang harus jelas? Ya, tetapi Anda harus selalu memprogram sesuai dengan KISS.

Mungkin kode Anda lebih efisien / tampan / elegan daripada pendekatan yang lebih mudah, idiot-bukti? Maka Anda perlu bertanya pada diri sendiri: apakah saya perlu melakukan ini? Sekali lagi, jika jawabannya tidak, maka jangan lakukan itu!

Jika setelah semua ini, Anda masih berpikir Anda perlu dan ingin melakukannya dengan cara FP, maka tentu saja lakukanlah. Percayai insting Anda, mereka lebih cocok untuk kebutuhan Anda daripada kebanyakan orang di forum apa pun :)

Arnab Datta
sumber
jangan ragu untuk menjelaskan alasan downvote
Arnab Datta