Автор оригіналу використовував символ#
для коментарів, але Друкарня не відображає такий код коректно, і коментарі зливаються з іншими частинами коду. Читати коментарі на телефонах стає ще складніше через автоматичне перенесення рядків. Тому я вирішив замінити символ#
на стандартний//
. Майте це на увазі.
Перед усім, ми повинні чітко уявити, що ми намагаємося досягти. Це хороша ідея підготувати детальний опис граматики, але в цьому посібнику я буду триматися більш неформального стилю, тому ось мова за допомогою прикладів:
// Це коментар
println("Hello World!");
println(2 + 3 * 4);
// Функції вводяться за допомогою "lambda" або "λ"
fib = lambda (n) if n < 2 then n else fib(n - 1) + fib(n - 2);
println(fib(15));
print-range = λ(a, b) // "λ" синонім до "lambda"
if a <= b then { // `then` тут, необов'язкове, як видно
print(a);
if a + 1 <= b {
print(", ");
print-range(a + 1, b);
} else println(""); // перехід на новий рядок
};
print-range(1, 5);
Зверніть увагу, що імена ідентифікаторів можуть містити символ мінуса (print-range
). Це питання особистого смаку: я завжди ставлю пробіли навколо операторів, мені не дуже подобається camelCaseNames, і дефіс виглядає краще, ніж підкреслення. Чудова річ у створенні своєї мови - це можливість робити все так, як вам подобається. :)
Вивід:
Hello World!
14
610
1, 2, 3, 4, 5
Мова схожа на JavaScript, але відрізняється. По-перше, тут немає операторів (statements), лише вирази (expressions).
Вираз повертає значення і може бути використаний на місці будь-якого іншого виразу. Крапки з комою потрібні для розділення виразів у "послідовності". Фігурні дужки, {
та }
, створюють таку послідовність і самі є виразом. Їх значення - це значення, яке повертає останній вираз. Наступне є правильною програмою:
a = {
fib(10); // не має побічних ефектів, але все одно обчислюється
fib(15) // останньої крапки з комою може не бути
};
print(a); // вихід: 610
Функції вводяться за допомогою одного з ключових слів lambda
або λ
(вони є синонімами). Після ключового слова має бути (можливо, пустий) список змінних, розділених комами у дужках, як у JavaScript — це назви аргументів. Тіло функції є одним виразом, але воно може бути послідовністю, обгорнутою у {…}
. Немає оператора return
(немає операторів) — останній вираз, що обчислюється в функції, визначає значення, яке повертається її викликачу.
Немає var
. Для введення нових змінних можна використовувати те, що JavaScript-розробники називають "IIFE"
. Використовуйте lambda
, оголошуйте змінні як аргументи. Змінні мають область видимості функції, а функції є замиканнями — так, як у JavaScript.
Навіть if
є сам по собі виразом. У JavaScript ви могли б досягти цього ефекту за допомогою тернарного оператора:
a = foo() ? bar() : baz(); // JavaScript
a = if foo() then bar() else baz(); // λanguage
Ключове слово then
є необов'язковим, коли гілка починається з відкритої фігурної дужки ({
), як можна побачити в прикладі print-range
вище. В іншому випадку воно обов'язкове. Ключове слово else
обов'язкове, якщо альтернативна гілка присутня. Знову ж таки, then
і else
приймають як тіло один вираз, але ви можете {
групувати}
кілька виразів, використовуючи фігурні дужки та крапки з комами. Коли відсутня гілка else
і умова є false
, результат виразу if
є false
. Говорячи про це, false
- ключове слово, що позначає єдине хибне значення в нашій λanguage:
if foo() then print("OK");
виведе "OK"
тільки тоді, коли результат виклику foo()
НЕ дорівнює false
. Є також ключове слово true
для повноти, але, справді, все, що не є false
(за оператором ===
у JavaScript), буде розглядатися як true в умовних виразах (включаючи число 0
і пустий рядок ""
).
Також слід зауважити, що немає потреби вимагати дужок навколо умови if
. Це не викличе виключення, якщо ви їх додасте, але, оскільки відкрита дужка починає вираз, вони просто зайві.
Весь програмний код розбирається так, ніби він вбудований у фігурні дужки, тому після кожного виразу потрібно ставити крапку з комою. Останній вираз може бути винятком.
Отже, це наша маленька λanguage. Вона не обов'язково є хорошою. Синтаксис виглядає миленьким, але в ньому є свої пастки. Багато чого не вистачає, наприклад, об'єктів або масивів; ми не зосереджуємося на них, тому що вони не є важливими для нашого подорожі. Якщо ви зрозуміли весь цей матеріал, ви зможете легко реалізувати їх.
У наступному розділі ми напишемо парсер для λanguage.