Мова, заснована на обмеженні кількості аргументів, переданих функціям


16

Ідея натхненна тим фактом, що оператори, такі як +, -,% тощо, можуть розглядатися як функції з одним або двома переданими аргументами і без побічних ефектів. Якщо припустити, що я або хтось інший пише мову, яка зупиняє передачу більше двох аргументів, а також працює лише через зворотне значення:

а) чи призвела б така мова до легшого розуміння коду?

б) чи чіткіше буде потік коду? (змушений робити більше кроків, потенційно менше взаємодій "приховано"

в) чи зробили б обмеження мову незмінно об'ємною для складніших програм.

г) (бонус) будь-які інші коментарі щодо плюсів та мінусів

Примітка:

Ще потрібно прийняти два рішення - перше - чи дозволити введення користувачем зовні main () або його еквівалента, а також, яке правило буде щодо того, що відбувається при передачі масивів / структур. Наприклад, якщо хтось хоче, щоб одна функція додала кілька значень, він може обійти обмеження, зв’язавши його в масив. Це можна зупинити, не дозволяючи масиву чи структурі взаємодіяти між собою, що все одно дозволить вам, наприклад, розділити кожне число на різну суму, залежно від його позиції.


4
Привіт. Списки плюсів і мінусів, як правило, дають погані відповіді. Чи є спосіб переформулювати запитання, щоб все-таки отримати необхідну інформацію, але в іншому форматі?
MetaFight

22
Ваші міркування навіть для мене не мають сенсу. У деяких функцій є мало аргументів, тож обмежимо всі функції? Зазвичай, коли пропонуються довільні обмеження, є причина, яку потрібно отримати. Я не бачу, що це могло б отримати тебе.

2
Не в тому, що з питаннями "що робити" щось суттєво не так (хоча на них часом важко відповісти, як сказав @MetaFight), але якщо навіть ви, хто подумав про це і піклувався, щоб задати питання, насправді не можете назвати ім'я користь, тоді я цілком впевнений, що моя початкова реакція "що? ні! це глупо, навіщо ти це робиш"?

6
Існує досить багато мов, які дозволяють лише один аргумент на функцію: все, що базується на обчисленні лямбда. В результаті , як правило , являє собою функцію , приймаючу один аргумент - список, або функція , яка повертає функцію , яка приймає наступний аргумент , поки все аргументи не будуть оброблені: result = f(a)(b)…(z). Це стосується сімейства мов ML, таких як Haskell, але також концептуально іншими мовами, такими як Lisp, JavaScript або Perl.
амон

3
@Orangesandlemons: Гаразд, тоді я можу кодувати довільну кількість цілих чисел у межах одного цілого числа, використовуючи просто множення та додавання (для кодування) та ділення та віднімання (для декодування). Отже, вам також потрібно заборонити цілі числа чи принаймні множення, додавання, ділення та віднімання. (Одним із наслідків сили програмування є те, що ви можете кодувати майже все, використовуючи майже все, і, таким чином, обмежувати речі - це дійсно, дуже важко. Загалом, обмеження насправді нічим не «обмежують», вони просто дратують програмістів.)
Йорг Ч Міттаг

Відповіді:


40

Роберт К. Мартін у своїй книзі "Чистий код" рекомендує наполегливо використовувати функції з максимум 0, 1 або 2 параметрами, тому принаймні є один досвідчений автор книги, який вважає, що код стає чистішим за допомогою цього стилю (проте він напевно, тут не найвищий авторитет, і його думки є дискусійними).

Там, де Боб Мартін правильний IMHO, це: функції з 3 і більше параметрами часто є індикаторами кодового запаху. У багатьох випадках параметри можуть бути згруповані разом для формування комбінованого типу даних, в інших випадках це може бути індикатором для функції, яка робить занадто багато.

Однак я не думаю, що було б гарною ідеєю вигадувати нову мову для цього:

  • якщо ви дійсно хочете застосувати таке правило протягом усього коду, вам просто потрібен інструмент аналізу коду для існуючої мови, не потрібно для цього вигадувати абсолютно нову мову (наприклад, для C # щось, на зразок 'fxcop', можливо, може бути використане ).

  • інколи поєднання параметрів з новим типом просто не здається клопоту, інакше це стане чисто штучним поєднанням. Дивіться, наприклад, цей File.Openметод із .Net Framework. Це потребує чотирьох параметрів, і я впевнений, що дизайнери цього API зробили це навмисно, тому що вони думали, що це буде найбільш практичним способом надання різних параметрів функції.

  • іноді існують реальні сценарії, коли більш ніж 2 параметри спрощують речі з технічних причин (наприклад, коли вам потрібно зіставлення 1: 1 до існуючого API, де ви зобов'язані використовувати прості типи даних, і не можете комбінувати різні параметри в один спеціальний об'єкт)


16
Запах з кількома параметрами часто різні параметри насправді належать разом. Візьмемо для прикладу розрахунок індексу маси тіла, ІМТ. Це функція довжини і ваги людини. f (довжина, вага), але ці два параметри дійсно належать разом, тому що ви коли-небудь зробили цей розрахунок з ростом однієї людини та вагою іншої? Отже, щоб представити це краще, ви отримаєте f (людина), де людина може мати інтервал ваги, довжини.
Пітер Б

@PieterB: звичайно, дивіться мою редакцію.
Док Браун

5
Крихітна, крихітна мова: «може вказувати на запах коду» Чи не запах коду за визначенням не є лише ознакою того, що вам слід щось переглянути, навіть якщо ви в кінцевому рахунку не змінили код? Тому запах коду не буде "вказаний". Якщо конкретний аспект вказує на можливість виникнення проблеми, вона є код запах. Ні?
jpmc26

6
@ jpmc26: З іншої точки зору, запах коду є можливою проблемою, а не вказівкою на один ;-) Все залежить від точного визначення запаху коду (і як тільки він пахне, він пішов погано, чи не так ?)
гофмале

3
@PieterB Хтось насправді це робить, хоча? Тепер вам потрібно створювати новий екземпляр Person щоразу, коли ви просто хочете обчислити ІМТ з двома довільними значеннями. Звичайно, якщо у вашій програмі для початку вже використовуються люди, і ви часто виявляєте, що робите щось на зразок f (person.length, person.height), ви могли б трохи очистити, але створення нових об'єктів спеціально для групових параметрів здається непосильним.
Адвокати

47

Є багато мов, які вже працюють таким чином, наприклад Haskell. У Haskell кожна функція бере рівно один аргумент і повертає рівно одне значення.

Завжди можна замінити функцію, яка приймає n аргументів, функцією, яка бере аргументи n-1 і повертає функцію, яка приймає кінцевий аргумент. Застосовуючи це рекурсивно, завжди можна замінити функцію, яка приймає довільну кількість аргументів, функцією, яка приймає рівно один аргумент. І це перетворення може здійснюватися механічно, за алгоритмом.

Це називається Frege-Schönfinkeling, Schönfinkeling, Schönfinkel-Currying, або Currying, після Хаскелла Керрі, який широко його досліджував у 50-х роках, Мойсея Шенфінкеля, який описав це в 1924 році, і Готлоба Фреге, який передбачив це в 1893 році.

Іншими словами, обмеження кількості аргументів має саме нульовий вплив.


2
Тобто, якщо ви дозволяєте повернути функції, звичайно. Навіть якщо ні, все, що вам потрібно зробити, - це наступна функція, яка називається в основній програмі. Тобто у вас може бути 1 + 1 + 1, де перше додавання - це функція, яка повертає функцію для додаткового додавання, або її можна просто викликати двічі. Останній стиль був би теоретично чистішим, чи я помиляюся?

5
"має рівно нульовий вплив" - питання ОП полягало у тому, чи зміниться чи зменшується читабельність коду, і я думаю, ви не заявляєте, що таке дизайнерське рішення для мови не впливає на це, чи не так?
Doc Brown

3
@DocBrown З пристойною потужністю та перевантаженням оператора я можу взяти мовою каррі і зробити його схожим на неквапливу мову. Приклад: f *(call_with: a,b,c,d,e) Перевантажувати, call_with :щоб почати ланцюг, ,подовжувати ланцюг, а *на LHS викликати f, передаючи йому кожен вміст ланцюга по одному. Досить слабка система перевантаження оператора просто робить синтаксис громіздким, але це вина системи перевантаження оператора більше ніж усе.
Якк

Власне, currying Haskell зводить функцію з n аргументів до функції з одним аргументом, що повертає іншу функцію з n - 1 аргументами.
Райан Райх

2
@RyanReich Ви праві, що ви можете бачити "привид" "кількості аргументів" функції Haskell в її підписі типу. Це привид, а не справжній підпис, тому що в цілому ви не можете знати, чи є остання змінна типу підпису також функціональним типом. У будь-якому випадку цей привид, який там присутній, не скасовує того, що в Haskell всі функції беруть 1 аргумент і повертають або нефункціональне значення, або іншу функцію, яка також приймає 1 аргумент. Це вбудовано в асоціативність ->: a-> b-> c - a>> (b-> c). Тож ви здебільшого помиляєтесь тут.
Ян

7

Останні кілька тижнів я витрачав деякий час на спробу вивчення мови комп'ютера J. У J в значній мірі все є оператором, тому ви отримуєте лише "монади" (функції, які мають лише один аргумент) та "діади" (функції з точно двома аргументами). Якщо вам потрібно більше аргументів, вам доведеться або надати їх у масиві, або надати їх у "полях".

J може бути дуже стислим, але, як і його попередник APL, він також може бути дуже виразним - але це, головним чином, результат мети творця наслідувати математичну стислість. Можна зробити програму J більш зрозумілою, використовуючи імена, а не символи для створення операторів.


ах, значить, це дозволяє масивам взаємодіяти між собою.

5

Мова, заснована на тому, як вона стримує розробника, залежить від припущення, що розробник мови розуміє потреби кожного програміста краще, ніж програміст розуміє ці потреби. Бувають випадки, коли це фактично справедливо. Наприклад, обмеження в багатопотоковому програмуванні, що вимагає синхронізації за допомогою мютексів і семафорів, вважаються багатьма "хорошими", оскільки більшість програмістів абсолютно не знають про основні складні для машини складності, які ці обмеження приховують від них. Крім того, мало хто хоче повністю зрозуміти нюанси багатопотокового алгоритму збору сміття; мова, яка просто не дозволяє зламати алгоритм GC, є кращою перед тією, яка змушує програміста усвідомлювати занадто багато нюансів.

Вам доведеться зробити вагомий аргумент, чому, як розробник мови, ви розумієте, що аргумент передається набагато краще, ніж програмісти, які використовують вашу мову, що є цінністю у тому, щоб заважати їм робити те, що вважаєте шкідливим. Я думаю, що це було б важким аргументом.

Ви також повинні знати , що програмісти будуть працювати навколо ваших обмежень. Якщо їм потрібно 3 або більше аргументів, вони використовуватимуть такі методи, як currying, щоб перетворити їх на виклики менше аргументів. Однак це часто виникає за рахунок читабельності, а не для поліпшення.

Більшість мов, які я знаю з цим правилом, - це esolangs, мови, призначені продемонструвати, що ви дійсно можете працювати з обмеженим набором функціональних можливостей. Зокрема, езоланги, де кожен символ є кодовим кодом, мають тенденцію обмежувати кількість аргументів, просто тому, що їм потрібно тримати список недокорів.


Це найкраща відповідь.
Джаред Сміт

1

Вам знадобляться дві речі:

  • Закриття
  • Складений тип даних

Я додам математичний приклад, щоб пояснити відповідь, написану Йоргом У Міттагом .

Розглянемо функцію Гаусса .

Функція Гаусса має два параметри своєї форми, а саме середнє (центральне положення кривої) та дисперсію (пов'язану з шириною імпульсу кривої). Окрім двох параметрів, потрібно також надати значення вільної змінної x, щоб оцінити її.

На першому кроці ми створимо функцію Гаусса, яка приймає всі три параметри, а саме середню, дисперсію та вільну змінну.

На другому кроці ми створюємо складений тип даних, який поєднує середнє значення та дисперсію в одне.

На третьому кроці ми створюємо параметризацію функції Гаусса, створюючи закриття функції Гаусса, прив'язаної до складеного типу даних, який ми створили на другому кроці.

Нарешті, ми оцінюємо закриття, створене на третьому кроці, передаючи йому значення вільної змінної x.

Отже, структура:

  • Оцінити (обчислення)
    • Параметризований гаусський (закриття: формула, плюс деякі зв'язані змінні)
      • GaussianParameters (складений тип даних)
        • Середнє значення)
        • Варіантність (значення)
    • X (значення вільної змінної)

1
  1. Практично на будь-якій мові програмування ви можете передавати певний тип списку, масиву, коррекції, запису чи об’єкта як єдиний аргумент. Єдина мета - утримувати інші предмети, а не передавати їх функції окремо. Деякі Java IDE навіть мають функцію " Extract Parameter Object ", щоб зробити саме це. Внутрішньо Java реалізує змінну кількість аргументів, створюючи та передаючи масив.

  2. Якщо ви дійсно хочете робити те, про що ви говорите, в найчистішому вигляді, вам потрібно розглянути читання лямбда. Це саме те, що ви описуєте. Ви можете шукати в Інтернеті, але опис, який мав сенс для мене, був у видах "Мови програмування" .

  3. Подивіться на мови програмування Haskell та ML (ML простіше). Вони обидва базуються на лямбдальному обчисленні і концептуально мають лише один параметр на функцію (якщо трохи примружити).

  4. Пункт 2 Джоша Блоха: "Подумайте про будівельника, стикаючись з багатьма параметрами конструктора." Ви можете бачити, наскільки це багатослівне , але радіти працювати з API, написаним таким чином.

  5. Деякі мови назвали параметри, що є ще одним підходом до того, щоб зробити підписи величезних методів набагато простішими в навігації. Наприклад, Котлін назвав аргументи .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.