Чому ми не досліджуємо більше, щоб скласти гарантії часу?


12

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

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

Зараз мені цікаво: якщо більш сильні статичні гарантії призводять до більш задокументованого та безпечного коду, то чому б ми не досліджували більше в цьому напрямку?

Прикладом чогось, що, здається, відсутнє, може бути мова, яка замість визначення загального intтипу, що має діапазон, визначений кількістю бітів базової архітектури, може мати діапазони (у наступному прикладі Int [a..b]описується цілий тип між a і b включено):

a : Int [1..24]
b : Int [1..12]
a + b : Int [2..36]
a - b : Int [-11..23]
b - a : Int [-23..11]

або (беручи це від Ада):

a : Int [mod 24]
b : Int [mod 24]
a + b : Int [mod 24]

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

a : Int [-3..24]
b : Int [3..10]

потім:

a / b

ніколи не буде визначено.

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


2
Паскаль має цілі типи піддіапазонів (тобто 1960-ті роки), але, на жаль, більшість реалізацій перевіряють їх лише під час виконання (int (-1..4) - це призначення, сумісне з int (100..200) під час компіляції). Вигоди від цього є обмеженими, і контрактне програмування розширює ідею в кращому напрямку (наприклад, Ейфель). Такі мови, як C #, намагаються отримати деякі з цих переваг з атрибутами, я не використовував їх, тому не знаю, наскільки вони корисні на практиці.

1
@ Ӎσᶎ: Атрибути в C # - це лише класи метаданих, тому будь-яка перевірка даних відбуватиметься під час виконання.
Роберт Харві

8
Звідки ви знаєте, що щодо цього мало досліджень? Спробуйте googling dependent typeабо refinement type.
Філ

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

1
@Robert Harvey: Те, що ADA надає більше гарантій, не означає, що компілятор вловлює всі помилки, це лише зробить помилки менш імовірними.
Джорджіо

Відповіді:


11

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

Концепції, які, на мою думку, ви шукаєте, називаються формальною верифікацією та контрактним програмуванням , де останнє - це сприятливий для програмістів спосіб зробити перший. У програмі, заснованому на контракті, ви спочатку записуєте свій код як звичайний, а потім вставляєте в код так звані контракти . Мовою, яка лежить на основі цієї парадигми, є Spec # від Microsoft Research, а також функціонально схоже, але трохи менш симпатичне розширення кодових контрактів для C #, яке ви можете спробувати в Інтернеті (вони також мають подібні інструменти для інших мов, перевірте зростання4fun ). Згаданий вами "int з діапазоном типу" відображатиметься двома контрактами у функції:

Contract.Requires(-3 <= a && a <= 24);
Contract.Requires( 3 <= b && b <= 10);

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

Під капотом кодові контракти зазвичай поєднуються зі знаннями про внутрішню роботу (оперативну семантику) мови програмування до переліку умов перевірки . Цей список представляє в основному одне велике логічне судження з вільними змінними - входами вашої програми. Якщо пропозиція справедлива для всіх можливих призначень змінних, тоді програма вважається правильною. Щоб перевірити, чи це так, чи слід, SMT Proverп РP(x1,x2,...,xn)nPвикористовується. З боку CS, ці два є найважливішими частинами процесу - створення умов перевірки є складним, а SMT - це повна NP або не визначена проблема, залежно від розглянутих теорій. Існує навіть конкуренція для вирішувачів SMT, тож, безумовно, слід вивчити це. Крім того, існують альтернативні підходи до використання SMT для формальної перевірки, такі як перерахування простору стану, символічна перевірка моделі, перевірка обмеженої моделі та багато інших, які також досліджуються, хоча SMT є, afaik, в даний час найбільш "сучасним" підходом.

Щодо меж загальної ідеї:

  • Як було сказано раніше, доведення коректності програми є важкою обчислювальною проблемою, тому може бути можливим, що перевірка часу компіляції програми з контрактами (або іншою формою специфікації) займає дуже багато часу або може бути навіть неможливою. Застосовуючи евристику, яка працює добре більшість часу, це найкраще, що можна зробити.
  • Чим більше ви задаєте про вашу програму, тим вище стає ймовірність наявності помилок в описі самого . Це може призвести до помилкових позитивних результатів (перевірка часу компіляції не вдається, навіть якщо все не містить помилок) або помилкового враження про безпеку, навіть якщо у вашій програмі все ще є помилки.
  • Складання контрактів або технічних характеристик - це справді копітка робота, і більшість програмістів ліниво це робити. Спробуйте написати програму C # з кодовими договорами скрізь, через деякий час ви подумаєте "давай, це справді потрібно?". Ось чому формальна перевірка, як правило, використовується лише для розробки обладнання та критично важливих для безпеки систем, таких як програмне забезпечення, що контролює літаки або автомобілі.

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


Чи не може бути можливим генерувати залежні типи чи контракти з комбінації прикладних тестів (ив) та нетипізованого коду, враховуючи певну "стратегію", яку ви можете вибрати залежно від вашого проекту?
aoeu256
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.