Bahasa berdasarkan pembatasan jumlah argumen yang diteruskan ke fungsi

16

Idenya terinspirasi oleh operator fakta seperti +, -,%, dll. Dapat dilihat sebagai fungsi dengan satu atau dua argumen yang dilewati, dan tidak ada efek samping. Dengan asumsi saya, atau orang lain, menulis bahasa yang menghentikan lebih dari dua argumen agar tidak diteruskan, dan juga hanya berfungsi melalui nilai balik:

a) apakah bahasa seperti itu mengarah pada kode yang lebih mudah dipahami?

b) apakah alur kode menjadi lebih jelas? (dipaksa ke langkah yang lebih banyak, dengan interaksi yang lebih sedikit berpotensi 'tersembunyi'

c) akankah pembatasan membuat bahasa menjadi sangat besar untuk program yang lebih kompleks.

d) (bonus) komentar lain tentang pro / kontra

catatan:

Dua keputusan masih harus dibuat - yang pertama adalah apakah mengizinkan input pengguna di luar main () atau yang setara, dan juga apa aturannya mengenai apa yang terjadi ketika melewati array / struktur. Sebagai contoh, jika seseorang menginginkan fungsi tunggal untuk menambahkan beberapa nilai, ia dapat menyiasati batasan dengan menggabungkannya menjadi sebuah array. Ini dapat dihentikan dengan tidak mengizinkan array atau struct dari berinteraksi dengan dirinya sendiri, yang masih memungkinkan Anda untuk, misalnya, membagi setiap angka dengan jumlah yang berbeda, tergantung pada posisinya.


sumber
4
Hai. Daftar Pro dan Kontra cenderung membuat jawaban yang buruk. Apakah ada cara Anda dapat menguraikan kembali pertanyaan Anda untuk tetap mendapatkan informasi yang Anda butuhkan tetapi dalam format lain?
MetaFight
22
Alasanmu bahkan tidak masuk akal bagiku. Beberapa fungsi memiliki beberapa argumen, jadi mari kita batasi semua fungsi? Biasanya ketika seseorang mengusulkan pembatasan sewenang-wenang, ada alasan, sesuatu yang harus diperoleh. Saya tidak bisa melihat apa yang mungkin bisa Anda dapatkan.
2
Bukannya ada sesuatu yang secara inheren salah dengan pertanyaan 'bagaimana jika' (meskipun mereka kadang-kadang sulit dijawab seperti yang dikatakan @MetaFight), tetapi jika bahkan Anda, yang memikirkan hal itu dan cukup peduli untuk mengajukan pertanyaan, tidak dapat benar-benar menyebutkan nama manfaat, maka saya cukup yakin reaksi awal saya tentang "apa? tidak! itu bodoh mengapa Anda melakukan itu" adalah akurat.
6
Ada beberapa bahasa yang hanya memungkinkan satu argumen per fungsi: apa pun berdasarkan kalkulus lambda. Hasilnya biasanya adalah fungsi mengambil daftar argumen tunggal, atau fungsi mengembalikan fungsi yang mengambil argumen berikutnya sampai semua argumen telah diproses: result = f(a)(b)…(z). Ini adalah kasus dalam keluarga bahasa ML seperti Haskell, tetapi juga secara konseptual dalam bahasa lain seperti Lisp, JavaScript, atau Perl.
amon
3
@Orangesandlemons: Oke, maka saya bisa menyandikan bilangan bulat sembarang dari bilangan bulat tunggal dengan hanya menggunakan perkalian dan penambahan (untuk pengodean) dan pembagian dan pengurangan (untuk pengodean ulang). Jadi, Anda perlu melarang bilangan bulat juga, atau setidaknya perkalian, penambahan, pembagian, dan pengurangan. (Salah satu konsekuensi dari kekuatan pemrograman adalah bahwa Anda dapat mengkodekan hampir semua hal menggunakan hampir semua hal, dan dengan demikian membatasi hal-hal sangat, sangat sulit. Secara umum, pembatasan tidak benar-benar "membatasi" apa pun, mereka hanya mengganggu pemrogram.)
Jörg W Mittag

Jawaban:

40

Robert C. Martin dalam bukunya "Clean Code" sangat merekomendasikan penggunaan fungsi dengan 0, 1 atau 2 parameter maksimal, jadi setidaknya ada satu penulis buku berpengalaman yang berpikir kode menjadi lebih bersih dengan menggunakan gaya ini (namun, ia jelas bukan otoritas ultimatif di sini, dan pendapatnya bisa diperdebatkan).

Di mana Bob Martin IMHO benar adalah: fungsi dengan 3 atau lebih parameter sering merupakan indikator untuk bau kode. Dalam banyak kasus, parameter mungkin dikelompokkan bersama untuk membentuk tipe data gabungan, dalam kasus lain, dapat menjadi indikator untuk fungsi yang hanya melakukan terlalu banyak.

Namun, saya tidak berpikir itu akan menjadi ide yang baik untuk menciptakan bahasa baru untuk ini:

  • jika Anda benar-benar ingin menegakkan aturan seperti itu di seluruh kode Anda, Anda hanya perlu alat analisis kode untuk bahasa yang ada, tidak perlu menciptakan bahasa yang sama sekali baru untuk ini (misalnya, untuk C # sesuatu seperti 'fxcop' mungkin dapat digunakan ).

  • kadang-kadang, menggabungkan parameter ke tipe baru sepertinya tidak sebanding dengan kerumitannya, atau itu akan menjadi kombinasi artifisial murni. Lihat, misalnya, metode iniFile.Open dari framework .Net. Dibutuhkan empat parameter, dan saya cukup yakin para perancang API melakukan ini dengan sengaja, karena mereka pikir itu akan menjadi cara paling praktis untuk memberikan parameter yang berbeda ke fungsi.

  • kadang-kadang ada skenario dunia nyata di mana lebih dari 2 parameter membuat segalanya lebih sederhana karena alasan teknis (misalnya, ketika Anda membutuhkan pemetaan 1: 1 ke API yang ada di mana Anda terikat pada penggunaan tipe data sederhana, dan tidak dapat menggabungkan berbagai parameter menjadi satu objek khusus)

Doc Brown
sumber
16
Bau dengan beberapa parameter seringkali merupakan parameter berbeda yang sebenarnya dimiliki bersama. Ambil contoh perhitungan indeks massa tubuh, BMI. Ini adalah fungsi dari panjang dan berat seseorang. f (panjang, berat), tetapi kedua parameter tersebut benar-benar saling memiliki karena apakah Anda pernah melakukan perhitungan ini dengan tinggi satu orang dan berat orang lain? Jadi untuk menyatakan bahwa lebih baik Anda akan mendapatkan f (orang) di mana orang dapat memiliki antarmuka berat, panjang.
Pieter B
@PieterB: tentu saja, lihat edit saya.
Doc Brown
5
Tiny, bahasa kecil nitpick: "mungkin menunjukkan bau kode" Bukankah definisi kode hanya indikasi bahwa Anda harus mempertimbangkan kembali sesuatu, bahkan jika Anda akhirnya tidak mengubah kode? Jadi bau kode tidak akan "ditunjukkan." Jika aspek tertentu menunjukkan kemungkinan masalah, itu adalah bau kode. Tidak?
jpmc26
6
@ jpmc26: Dari sudut pandang lain, bau kode adalah masalah yang mungkin, bukan indikasi satu ;-) Itu semua tergantung pada definisi yang tepat dari bau kode (dan begitu bau, itu sudah buruk, bukankah begitu ?)
hoffmale
3
@PieterB Apakah ada yang benar-benar melakukan ini? Sekarang Anda harus membuat instance Person baru setiap kali Anda hanya ingin menghitung BMI dengan dua nilai arbitrer. Tentu, jika aplikasi Anda sudah menggunakan Orang untuk memulai dan Anda sering melakukan sesuatu seperti f (person.length, person.height) Anda bisa membersihkannya sedikit tetapi membuat objek baru khusus untuk parameter grup tampaknya berlebihan.
Lawyerson
47

Ada banyak bahasa yang sudah berfungsi seperti ini, misalnya Haskell. Di Haskell, setiap fungsi mengambil tepat satu argumen dan mengembalikan tepat satu nilai.

Itu selalu mungkin untuk mengganti fungsi yang mengambil n argumen dengan fungsi yang mengambil n-1 argumen dan mengembalikan fungsi yang mengambil argumen pamungkas. Menerapkan ini secara rekursif, selalu mungkin untuk mengganti fungsi yang mengambil sejumlah argumen sewenang-wenang dengan fungsi yang hanya membutuhkan satu argumen. Dan transformasi ini dapat dilakukan secara mekanis, dengan suatu algoritma.

Ini disebut Frege-Schönfinkeling, Schönfinkeling, Schönfinkel-Currying, atau Currying, setelah Haskell Curry yang meneliti secara ekstensif pada 1950-an, Moses Schönfinkel, yang menggambarkannya pada 1924, dan Gottlob Frege, yang meramalkannya pada 1893.

Dengan kata lain, membatasi jumlah argumen memiliki dampak nol.

Jörg W Mittag
sumber
2
Itu jika Anda mengizinkan fungsi dikembalikan, tentu saja. Bahkan jika tidak, yang harus Anda lakukan adalah memiliki fungsi berikutnya yang disebut dalam program utama. Yaitu Anda bisa memiliki 1 + 1 + 1 di mana penambahan pertama adalah fungsi yang mengembalikan fungsi untuk penambahan tambahan, atau itu bisa disebut dua kali. Secara teori, gaya yang terakhir akan lebih bersih, atau saya salah?
5
"memiliki dampak nol" - Pertanyaan OP adalah apakah readibilty kode akan meningkat atau menurun, dan saya kira Anda tidak mengklaim keputusan desain untuk suatu bahasa tidak berdampak pada hal itu, bukan?
Doc Brown
3
@DocBrown Dengan tenaga dan operator yang berlebihan, saya dapat menggunakan bahasa kari dan membuatnya terlihat seperti bahasa yang tidak terburu-buru. Contoh: f *(call_with: a,b,c,d,e) Overload call_with :untuk memulai rantai, ,untuk memperpanjang rantai, dan *pada LHS untuk memohon fdengan memberikan masing-masing isi rantai satu per satu. Sistem overloading operator yang cukup lemah hanya membuat sintaks menjadi rumit, tetapi itu adalah kesalahan dari sistem overloading operator lebih dari apa pun.
Yakk
Sebenarnya, haskell's currying mengurangi fungsi dengan argumen n ke fungsi dengan satu argumen mengembalikan fungsi lain dengan argumen n - 1.
Ryan Reich
2
@RyanReich Anda benar bahwa Anda dapat melihat "hantu" dari "jumlah argumen" dari fungsi Haskell dalam tanda tangan tipenya. Ini hantu daripada tanda tangan yang benar karena secara umum Anda tidak memiliki cara untuk mengetahui apakah variabel tipe terakhir dalam tanda tangan juga merupakan tipe fungsi. Bagaimanapun, hantu ini ada di sana tidak membatalkan fakta bahwa di Haskell semua fungsi mengambil 1 argumen dan mengembalikan nilai non-fungsi atau fungsi lain yang juga membutuhkan 1 argumen. Ini dibangun ke dalam asosiativitas ->: a-> b-> c adalah a -> (b-> c). Jadi Anda sebagian besar salah di sini.
Ian
7

Saya telah menghabiskan waktu beberapa minggu terakhir ini untuk belajar bahasa komputer. Di J, hampir semuanya adalah operator, jadi Anda hanya mendapatkan "monad" (fungsi yang hanya memiliki satu argumen) dan "dyad" (fungsi dengan tepat dua argumen). Jika Anda perlu lebih banyak argumen, Anda harus menyediakannya dalam array, atau memberikannya dalam "kotak".

J bisa sangat ringkas, tetapi seperti APL pendahulunya, ia juga bisa sangat samar - tetapi ini sebagian besar merupakan hasil dari tujuan pencipta untuk meniru kesederhanaan matematis. Dimungkinkan untuk membuat program J lebih mudah dibaca dengan menggunakan nama daripada karakter untuk membuat operator.

Alpheus
sumber
ah, jadi itu memungkinkan array untuk berinteraksi dengan diri mereka sendiri.
5

Bahasa yang didasarkan pada batasan pengembang tergantung pada asumsi bahwa pengembang bahasa memahami kebutuhan masing-masing programmer lebih baik daripada programmer memahami kebutuhan itu sendiri. Ada kasus di mana ini sebenarnya valid. Sebagai contoh, kendala pada pemrograman multithreaded yang memerlukan sinkronisasi menggunakan mutex dan semaphore dianggap oleh banyak orang sebagai "baik" karena sebagian besar programmer benar-benar tidak menyadari kompleksitas spesifik mesin yang mendasarinya yang disembunyikan oleh kendala tersebut. Demikian juga, hanya sedikit yang ingin memahami sepenuhnya nuansa algoritma pengumpulan sampah multithread; bahasa yang tidak memungkinkan Anda memecahkan algoritma GC lebih disukai daripada bahasa yang memaksa programmer untuk menyadari terlalu banyak nuansa.

Anda harus membuat argumen yang valid untuk alasan mengapa, sebagai pengembang bahasa, Anda memahami argumen yang lulus jauh lebih baik daripada programmer yang menggunakan bahasa Anda sehingga ada nilai dalam mencegah mereka melakukan hal-hal yang Anda anggap berbahaya. Saya pikir itu akan menjadi argumen yang sulit untuk dibuat.

Anda juga harus tahu bahwa programmer akan mengatasi kendala Anda. Jika mereka membutuhkan 3 argumen atau lebih, mereka akan menggunakan teknik seperti kari untuk mengubahnya menjadi panggilan argumen yang lebih sedikit. Namun, hal ini seringkali membutuhkan biaya keterbacaan, daripada meningkatkannya.

Sebagian besar bahasa yang saya tahu dengan aturan semacam ini adalah esolang, bahasa yang dirancang untuk menunjukkan bahwa Anda memang dapat beroperasi dengan serangkaian fungsi terbatas. Secara khusus, esolang di mana setiap karakter adalah opcode memiliki kecenderungan untuk membatasi jumlah argumen, hanya karena mereka perlu membuat daftar opcode singkat.

Cort Ammon - Pulihkan Monica
sumber
Ini jawaban terbaik.
Jared Smith
1

Anda akan membutuhkan dua hal:

  • Penutupan
  • Tipe data komposit

Saya akan menambahkan contoh matematika untuk menjelaskan jawaban yang ditulis oleh Jörg W Mittag .

Pertimbangkan fungsi Gaussian .

Fungsi Gaussian memiliki dua parameter untuk bentuknya, yaitu rata-rata (posisi tengah kurva) dan varians (terkait dengan lebar pulsa kurva). Selain dua parameter, kita juga perlu memberikan nilai variabel bebas xuntuk mengevaluasinya.

Pada langkah pertama, kami akan merancang fungsi Gaussian yang mengambil ketiga parameter, yaitu mean, varians, dan variabel bebas.

Pada langkah kedua, kami membuat tipe data komposit yang menggabungkan mean dan varians menjadi satu hal.

Pada langkah ketiga, kami membuat parameterisasi fungsi Gaussian dengan membuat penutupan fungsi Gaussian yang terikat dengan tipe data komposit yang kami buat di langkah kedua.

Akhirnya, kami mengevaluasi penutupan yang dibuat pada langkah ketiga dengan meneruskan nilai variabel bebas xke sana.

Karena itu strukturnya adalah:

  • Mengevaluasi (perhitungan)
    • ParameterizedGaussian (penutup: rumus, ditambah beberapa variabel terikat)
      • GaussianParameters (tipe data komposit)
        • Berarti (nilai)
        • Varians (nilai)
    • X (nilai variabel bebas)
rwong
sumber
1
  1. Di hampir semua bahasa pemrograman, Anda dapat melewatkan beberapa jenis daftar, larik, tupel, rekam, atau objek sebagai satu-satunya argumen. Satu-satunya tujuan adalah menyimpan item lain alih-alih meneruskannya ke fungsi satu per satu. Beberapa IDE Java bahkan memiliki fitur " Ekstrak Parameter Objek " untuk melakukan hal itu. Secara internal, Java mengimplementasikan sejumlah variabel argumen dengan membuat dan melewatkan array.

  2. Jika Anda benar-benar ingin melakukan apa yang Anda bicarakan dalam bentuk paling murni, Anda perlu melihat kalkulus lambda. Persis seperti yang Anda gambarkan. Anda dapat mencari web untuk itu, tetapi deskripsi yang masuk akal bagi saya adalah dalam Jenis dan Bahasa Pemrograman .

  3. Lihatlah bahasa pemrograman Haskell dan ML (ML lebih sederhana). Keduanya didasarkan pada kalkulus lambda dan secara konseptual hanya memiliki satu parameter per fungsi (jika Anda sedikit menyipit).

  4. Josh 2 Bloch's Item 2 adalah: "Pertimbangkan pembangun ketika dihadapkan dengan banyak parameter konstruktor." Anda dapat melihat bagaimana verbose ini didapat , tetapi senang bekerja dengan API yang ditulis dengan cara ini.

  5. Beberapa bahasa telah menamai parameter yang merupakan pendekatan lain untuk membuat tanda tangan metode besar lebih mudah dinavigasi. Kotlin telah menamai argumen misalnya.

GlenPeterson
sumber