Як перевірити / довести ортогональність мови програмування?


10

Я знаю концепцію ортогональності, але з точки зору мови програмування, чи є спосіб її перевірити / довести?

Наприклад, в C #, можна використовувати publicабо staticдля підпису методу. Ви можете використовувати або обидва, і обидва, і вони не заважатимуть один одному, тому вони є ортогональними один для одного, правда?

Моє запитання полягає в тому, як мені зрозуміти інші функції, зокрема функції, які не пов'язані між собою?

Чи всі функції повинні співіснувати / складатись разом?

Чи існує мова програмування, яка є ортогональною на 100%?


Почати з (найближчого) початку: мова складання?
Меттью Флінн

1
Щоб щось фактично довести, вам потрібно це формальне визначення. І якщо ваше визначення буде чимось таким же великим, як специфікація C #, доведення чого-небудь потребує багато роботи.
svick

Відповіді:


4

Я не впевнений, що ортогональність може слугувати корисною чи дійсною метрикою у випадку загальновизнаних мов високого порядку, таких як C #, оскільки вона вимагає розрізнення "операцій" та "операндів" - невеликих частин мови, які нелегко відрізняється такими мовами високого порядку, як C #.

Моє розуміння ортогональності ґрунтується на мові Assembler, де ортогональність набору інструкцій певного конкретного процесора або мікроконтролера вказувала, чи є деякі обмеження в операціях, які виконуються цим процесором або контролером залежно від типів даних. У ранні часи це було важливо, оскільки не кожен процесор підтримував операції з дробовими числами або числами різної довжини тощо.

У цьому відношенні я скоріше перевіряю ортогональність загальної проміжної мови, використовуючи мову Stack Machine як ціль для компілятора C #, а не самого C #.

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


6

Термін "ортогональність" - це термін мирянина для точного математичного поняття: мовні терміни утворюють початкову алгебру (подивіться це у Вікіпедії).

Це в основному означає "існує відповідність 1-1 між синтаксисом і значенням". Це означає: існує рівно один спосіб висловити речі, і, якщо ви можете помістити якийсь вираз у певне місце, то ви можете також ввести будь-який інший вираз.

Ще один спосіб думати про "ортогональний" - це те, що синтаксис підкоряється принципу заміни. Наприклад, якщо у вас є вираз із слотом для виразу, то будь-який вираз можна помістити туди, і результат все ще є синтаксично дійсною програмою. Крім того, якщо ви заміните

Хочу підкреслити, що "значення" не означає обчислювальний результат. Зрозуміло, що 1 + 2 і 2 + 1 обидва рівні 3. Однак терміни є різними і означають інший обчислення, навіть якщо він має однаковий результат. Сенс різний, подібно до того, як різні алгоритми сортування відрізняються.

Можливо, ви чули про "абстрактне синтаксичне дерево" (AST). Слово "абстрактне" тут означає саме "ортогональне". Технічно більшість AST насправді не є абстрактними!

Можливо, ви чули про мову програмування "С"? Позначення типу C не є абстрактними. Поміркуйте:

int f(int);

Отже, ось декларація функції повернення типу int. Тип вказівника на цю функцію задається:

int (*)(int)

Зверніть увагу, ви не можете записати тип функції! Позначення типу C смокче великий час! Це не абстрактно. Це не ортогонально. Тепер, припустимо, ми хочемо зробити функцію, яка приймає вищевказаний тип замість int:

int (*) ( int (*)(int) )

Все добре .. але .. що робити, якщо ми хочемо повернути це замість:

int (*)(int) (*) (int)

Вупи! Недійсний. Додаємо паролі:

(int (*)(int)) (*) (int)

Вупи! Це теж не працює. Ми повинні це зробити (це єдиний спосіб!):

typedef int (intintfunc*) (int);
intintfunc (*)(int)

Тепер це нормально, але використовувати тут typedef - це погано. C смокче. Це не абстрактно. Це не ортогонально. Ось як це зробити в ML, що є:

 int -> (int -> int)

Ми засуджуємо C на рівні синтаксису.

Гаразд, тепер давайте перемикати C ++. Ми можемо виправити дурість вище за допомогою шаблонів і отримати ML як нотацію (більш-менш):

fun<int, int>
fun< fun<int,int>, int>

але фактична система типу принципово хибна посиланнями: якщо Tце тип, то це T&тип? Відповідь вафлі: на рівні синтаксису, якщо у вас тип U = T &, тоді U & дозволено, але це просто означає T&: посилання на посилання є оригінальним посиланням. Це смокче! Він семантично порушує вимогу унікальності. Гірше: T & & не дозволено синтаксично: це порушує принцип заміни. Таким чином, посилання на C ++ розбивають ортогональність двома різними способами, залежно від часу зв'язування (розбору або аналізу типу). Якщо ви хочете зрозуміти, як це зробити правильно .. немає вказівників!

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


Отже, ви вважаєте, що ML є більш ортогональним, ніж інші? Що з Ліспом і Хаскеллом?
Джоан Венге

1
@joan: добре, lisp не має жодних функцій, тому він задовольняє вимогам у vaccuuo :)
Yttrill

@joan: Я не програміст Haskell, тому це важко сказати, але наявність в Haskell "надзвичайно високого функціонального рівня" вказує на сильну ортогональність: ви просто не можете мати цілісну реалізацію Monads або Arrow, якщо тільки решта мови має істотну "ортогональність"
Іттрил

Що ви думаєте про Паскаля. Здається, навантаження краще за C.
supercat

Я знаю, що мій коментар затримується майже на 4 роки, але я просто натрапив на нього. Ця відповідь неправильна майже у всьому. Навіть ціле "це єдиний шлях!" частина просто неправильна. Ви можете легко висловити, що без прикладу typedef int (*intintfunc())(int) { ... }- intintfunc - це функція, яка не бере аргументів і повертає вказівник на функцію, яка бере аргумент 1 int і повертає значення int.
Wiz

4

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

На практиці більшість людей говорять про ортогональність мов програмування з точки зору ступенів, а не бути повністю ортогональними чи ні. Коли знання про те, що робити щось в одному контексті, перекладається в інший контекст і "робить те, що ви очікуєте", ця мова вважається більш ортогональною. LISP вважається високо ортогональним, оскільки все є списком, але я не думаю, що можна сказати, що він на 100% ортогональний через деякі надмірності, які полегшують його використання. C ++ вважається не дуже ортогональним, тому що є багато маленьких "gotchas", де він не зовсім працює так, як ви думаєте.


3

Попередження, я нічого не знаю на цю тему.

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

Щодо C #, я думаю, що це ортогонально, оскільки більшість синтаксичних трюків ( foreachприходить в голову) є просто передніми для спеціально сформованих версій базової конструкції ( foreachстає forциклом). В цілому мова лише справді підтримує ведення справ поодиноким чином, навіть якщо синтаксичний цукор забезпечує додаткові способи їх виконання. І, нарешті, все це складається до MSIL(або як він називається в ці дні) і MSIL, ймовірно, є ортогональним.

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

Мої два центи.


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

Не do...whileможна використовувати такий ефект, як for? Я ніколи не чув, щоб про це вважали синтаксичним цукром.
Меттью Флінн

1
@MatthewFlynn: Ба! Вони сильно-синтаксичні цукор, ви можете просто замінити ітерацію рекурсивною функцією! ;)
FrustratedWithFormsDesigner

2
@FrustratedWithFormsDesigner: Це не просто синтаксичний цукор для GOTO?
Іван

2
@MatthewFlynn do whileгарантує виконання одного циклу та перевіряє стан після факту. forСпочатку перевіряє умову та не гарантує жодного виконання.
digitlworld

2

Моє запитання полягає в тому, як мені зрозуміти інші функції, зокрема функції, які не пов'язані між собою?

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

Це все. Це досить боляче робити.

Чи всі функції повинні співіснувати / складатись разом?

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

Усі структури даних працюють з усіма примітивними типами. Всі оператори виразів працюють з усіма типами. Це загальні визначення ортогональності. Але ви можете хотіти більше (або менше)

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

Також деякі типи насправді не дуже сумісні. Наприклад, Python дозволяє порівняти два об'єкти словника для "замовлення". Але розумного визначення "впорядкування" серед словників майже немає. Python визначає один, але це досить дискусійно. Чи робить цей особливий випадок, що словники не відповідають тесту на ортогональність?

Наскільки ортогональний "достатньо ортогональний"? Що ви повинні бачити , щоб бути щасливим зі ступенем ортогональности на вашій мові.


2

Перелік неортогональних ознак дійсно довгий у більшості мов програмування, наприклад

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

Це лише декілька, які мені спадають на думку, але є багато інших, а також іншими мовами.

Важко переконатися у відсутності тонких втручань між особливостями мови. Як зазначає CAR Hoare у своїй роботі "Підказки щодо дизайну мови програмування":

Частина мовного дизайну складається з інновацій. Ця діяльність призводить до нових мовних особливостей ізольовано. Найскладніша частина мовного дизайну полягає в інтеграції : вибір обмеженого набору мовних особливостей та полірування їх до тих пір, поки в результаті не вийде послідовна проста рамка, яка не має більш грубих країв.

Ймовірно, хорошим кроком до підвищення ортогональності є уніфікація понять (що йде у напрямку відповіді @ karl-bielfeld). Якщо все є, скажімо, список чи об’єкт, велика ймовірність, що конфліктів буде менше. Або замість того, щоб вкладати клас після роздумів, зробіть його основними особливостями.

Більшість статей з мов програмування доводять певні властивості мови (наприклад, звуковість типу) на підмножині ("ядрі") мови, яка формалізується. Тут ми повинні зробити навпаки, довести, що всі риси складаються благополучно. Крім того, це означає, що слід визначити, що означає "складати". Це означає «бігти»? (У цьому випадку посилання вище про крайовий регістр із динамічним та статичним введенням є безпечним). Це означає бути "безпечним"? Чи означає це бути передбачуваним з точки зору розробника?

Все це дуже цікаво - але теж дуже складно.

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