C # , Scala, Haskell, Lisp dan Python memiliki zip
perilaku yang sama : jika satu koleksi lebih panjang, ekor diabaikan secara diam-diam.
Ini bisa menjadi pengecualian yang dilemparkan juga, tetapi saya tidak mendengar adanya bahasa yang menggunakan pendekatan ini.
Ini membuatku bingung. Adakah yang tahu alasan mengapa zip
dirancang seperti itu? Saya kira untuk bahasa baru, ini dilakukan karena bahasa lain melakukannya dengan cara ini. Tapi apa alasan dasarnya?
Saya mengajukan pertanyaan faktual, berbasis sejarah di sini, bukan apakah seseorang menyukainya, atau apakah itu pendekatan yang baik atau buruk.
Pembaruan : Jika saya ditanya apa yang harus dilakukan, saya akan mengatakan - melemparkan pengecualian, cukup mirip dengan pengindeksan array (meskipun bahasa "lama" melakukan semua jenis sihir, bagaimana menangani indeks di luar batas, UB, memperluas array, dll).
sumber
zipWithIndex
menyediakan bilangan alami. Sekarang, bagian hanya hilang info - apa itu alasannya? :-) (btw. tolong posting ulang komentar Anda sebagai jawaban, terima kasih).Jawaban:
Ini hampir selalu seperti yang Anda inginkan, dan ketika tidak, Anda dapat mengisi sendiri.
Masalah utamanya adalah dengan semantik malas yang tidak Anda ketahui panjangnya saat pertama kali memulai
zip
, jadi Anda tidak bisa hanya melempar pengecualian di awal. Pertama-tama Anda harus mengembalikan semua elemen umum, lalu melemparkan pengecualian, yang tidak akan sangat berguna.Ini juga masalah gaya. Programmer imperatif terbiasa memeriksa kondisi batas secara manual di semua tempat. Pemrogram fungsional lebih suka konstruksi yang tidak dapat gagal dengan desain. Pengecualian sangat jarang. Jika ada cara bagi fungsi untuk mengembalikan default yang wajar, programmer fungsional akan menerimanya. Kompabilitas adalah raja.
sumber
zip
penerapannya saat ini. Melempar pengecualian hanya mengubah "berhenti menghasilkan" menjadi "melempar". Paragraf ketiga - mengembalikan elemen kosong untuk mencapai batas tidak boleh gagal, tetapi saya ragu FP dev akan memilih itu adalah desain yang bagus.zip
berdua urutan yang tak terbatas bersama-sama, Anda tidak tahu ukuran di awal. Pada paragraf ketiga, saya mengatakan default yang masuk akal . Mengembalikan kosong dalam kasus ini tidak masuk akal, sedangkan menjatuhkan ekor jelas.Karena tidak ada cara yang jelas untuk melengkapi ekornya. Pilihan apa pun tentang bagaimana melakukannya akan menghasilkan buntut yang tidak jelas.
Caranya adalah dengan secara eksplisit memperpanjang daftar terpendek Anda agar sesuai dengan panjang terpanjang dengan nilai yang Anda harapkan.
Jika zip melakukan itu untuk Anda, Anda tidak bisa tahu nilai apa yang diisi secara intuitif. Apakah itu menggilir daftar? Apakah itu mengulang nilai yang dipty? Apa nilai mempty untuk tipe Anda?
Tidak ada implikasi dalam hal apa zip yang bisa digunakan seseorang untuk intuisi bagaimana ekor akan diperpanjang, jadi satu-satunya hal yang masuk akal untuk dilakukan adalah bekerja dengan nilai-nilai yang tersedia daripada membuat beberapa yang mungkin tidak diharapkan oleh konsumen Anda.
Juga ingat Anda mengacu pada fungsi terkenal yang sangat spesifik dengan semantik terkenal tertentu. Tetapi itu tidak berarti Anda tidak dapat membuat fungsi yang serupa tetapi sedikit berbeda . Hanya karena ada fungsi umum yang berfungsi
x
, tidak berarti Anda tidak dapat memutuskan untuk tujuan tertentu yang ingin Anda lakukanx
dany
.Meskipun ingat alasan ini dan banyak fungsi gaya FP umum lainnya adalah umum, adalah karena mereka sederhana dan digeneralisasi sehingga Anda dapat mengubah kode Anda untuk menggunakannya dan mendapatkan perilaku yang Anda inginkan. Misalnya, dalam C # Anda bisa saja
Atau hal-hal sederhana lainnya. Pendekatan FP membuat modifikasi sangat mudah karena Anda dapat menggunakan kembali potongan-potongan serta memiliki implementasi menjadi sangat kecil seperti di atas yang membuat versi modifikasi Anda sendiri dari hal-hal yang sangat sederhana.
sumber
zip
dapat mengisi nol, yang seringkali merupakan solusi intuitif. Pertimbangkan tipenyazip :: [a] -> [b] -> [(Maybe a, Maybe b)]
. Memang, tipe hasilnya agak ^ H ^ H cukup tidak praktis, tetapi akan memungkinkan untuk dengan mudah menerapkan perilaku lain (jalan pintas, pengecualian) di atasnya.mempty
, objek memiliki null untuk mengisi ruang, tetapi Anda ingin itu harus datang dengan hal seperti itu untuk int dan tipe lainnya juga? Tentu, C # memilikidefault(T)
tetapi tidak semua bahasa melakukannya, dan bahkan untuk C # apakah itu perilaku yang sangat jelas ? Saya kira tidak