О людино, я з радістю намагаюся відповісти на це питання якнайкраще. Я сподіваюся, що зможу правильно навести свої думки в порядку.
Як зазначав @Doval і запитуючий зазначив (хоч і грубо), у вас насправді немає типової системи. У вас є система динамічних перевірок за допомогою тегів, яка в цілому набагато слабша, а також набагато менш цікава.
Питання "що таке система типів" може бути досить філософським, і ми могли б заповнити книгу з різними поглядами на цю проблему. Однак, оскільки це сайт для програмістів, я спробую зберегти свою відповідь максимально практичною (і насправді типи надзвичайно практичні в програмуванні, незважаючи на те, що деякі можуть подумати).
Огляд
Почнемо з того, що розберемося з штанами, перед тим як піти на більш офіційні основи. Система типу накладає структуру нашим програмам . Вони говорять нам, як ми можемо поєднувати різні функції та вирази разом. Без структури програми непідробні та дико складні, готові завдати шкоди при найменшій помилці програміста.
Написання програм із системою типу - це як керування доглядом у м'ятному стані - гальмо спрацьовує, двері безпечно закриваються, двигун змащений маслом і т. Д. Написання програм без системи типу - це як їзда на мотоциклі без шолома та з зробленими колесами з спагетті. Ви абсолютно не маєте контролю над своїм.
Обгрунтувати обговорення, скажімо , у нас є мова з літерним виразом num[n]
і str[s]
які представляють цифру п і рядок s, відповідно, і примітивні функції plus
і concat
, з імовірною змістом. Зрозуміло, ви не хочете мати можливість написати щось на кшталт plus "hello" "world"
або concat 2 4
. Але як ми можемо запобігти цьому? Апріорі , немає способу відрізнити число 2 від рядкового буквального "світу". Ми хотіли б сказати, що ці вирази повинні використовуватися в різних контекстах; вони мають різні типи.
Мови та типи
Давайте трохи відступимо: що таке мова програмування? Загалом, ми можемо розділити мову програмування на два шари: синтаксис та семантику. Їх також називають відповідно статикою і динамікою . Виявляється, типова система необхідна для опосередкування взаємодії між цими двома частинами.
Синтаксис
Програма - дерево. Не обманюйте рядки тексту, який ви пишете на комп'ютері; це лише людиночитані уявлення програми. Сама програма є абстрактним синтаксичним деревом . Наприклад, в C ми можемо написати:
int square(int x) {
return x * x;
}
Це конкретний синтаксис програми (фрагмента). Представлення дерева:
function square
/ | \
int int x return
|
times
/ \
x x
Мова програмування містить граматику, що визначає дійсні дерева цієї мови (може використовуватися конкретний або абстрактний синтаксис). Зазвичай це робиться, використовуючи щось на зразок позначення BNF. Я б припустив, що ви зробили це для мови, яку ви створили.
Семантика
Гаразд, ми знаємо, що таке програма, але це просто статична структура дерева. Імовірно, ми хочемо, щоб наша програма фактично щось обчислила . Нам потрібна семантика.
Семантика мов програмування - це багата область вивчення. Загалом, існує два підходи: денотаційна семантика та оперативна семантика . Денотаційна семантика описує програму, відображаючи її в деякій базовій математичній структурі (наприклад, натуральні числа, безперервні функції тощо). що надає сенс нашій програмі. Оперативна семантика, навпаки, визначає програму, детально описуючи її виконання. На мою думку, оперативна семантика є більш інтуїтивно зрозумілою для програмістів (в тому числі і я), тому давайте дотримуватись цього.
Я не буду розглядати, як визначити формальну оперативну семантику (деталі трохи залучені), але в основному ми хочемо таких правил, як:
num[n]
є цінністю
str[s]
є цінністю
- Якщо
num[n1]
і num[n2]
оцінити до цілих чисел n_1$ and $n_2$, then
плюс (num [n1], num [n2]) `оцінює ціле число $ n_1 + n_2 $.
- Якщо
str[s1]
і str[s2]
оцінює рядки s1 і s2, то concat(str[s1], str[s2])
оцінює рядок s1s2.
І т.д. Правила на практиці набагато формальніші, але ви отримуєте суть. Однак ми незабаром стикаємося з проблемою. Що відбувається, коли ми пишемо наступне:
concat(num[5], str[hello])
Гм. Це досить загадка. Ми ніде не визначили правило, як поєднати число з рядком. Ми могли б спробувати створити таке правило, але ми інтуїтивно знаємо, що ця операція є безглуздою. Ми не хочемо, щоб ця програма була дійсною. І таким чином нас невблаганно ведуть до типів.
Типи
Програма - це дерево, визначене граматикою мови. Програми мають значення за правилами виконання. Але деякі програми неможливо виконати; тобто деякі програми безглузді . Ці програми неправильно набрані. Таким чином, введення тексту характеризує змістовні програми мовою. Якщо програма добре набрана, ми можемо її виконати.
Наведемо кілька прикладів. Знову ж таки, як і з правилами оцінювання, я неформально представлю правила набору тексту, але їх можна зробити суворими. Ось кілька правил:
- Маркер форми
num[n]
має тип nat
.
- Маркер форми
str[s]
має тип str
.
- Якщо вираз
e1
має тип, nat
а вираз e2
має тип nat
, то вираз plus(e1, e2)
має тип nat
.
- Якщо вираз
e1
має тип, str
а вираз e2
має тип str
, то вираз concat(e1, e2)
має тип str
.
Таким чином, згідно з цими правилами, існує plus(num[5], num[2])
тип has nat
, але ми не можемо призначити тип plus(num[5], str["hello"])
. Ми говоримо, що програма (або вираз) добре набрана, якщо ми можемо призначити її будь-якого типу, і вона неправильно введена в іншому випадку. Система типу є здоровою, якщо можна виконати всі добре набрані програми. Haskell - звук; С - ні.
Висновок
Існують і інші погляди на типи. Типи в деякому сенсі відповідають інтуїтивістській логіці, і їх також можна розглядати як об'єкти в теорії категорій. Розуміння цих зв’язків є захоплюючим, але це не суттєво, якщо потрібно просто написати або навіть розробити мову програмування. Однак розуміння типів як інструменту контролю програмних формувань є важливим для проектування та розробки мови програмування. Я лише подряпав поверхню того, що може виражати тип. Я сподіваюся, ви вважаєте, що вони варті того, щоб їх включити до вашої мови.