Виклик
Ваше завдання полягає в тому, щоб створити перекладача для мови, схожої на ліс , який з цього моменту буде виведений назовні : GLisp . Програмний код для GLisp буде складатися з довільної кількості вкладених виразів, позначених дужками, у такій формі:
(func arg1 arg2 ...)
Зауважте, що інтерпретатор повинен передбачати сторонні символи пробілу до та після дужок, функцій та аргументів.
Типи
Ви будете реалізовувати чотири типи: Integer, List, Boolean та Function. Цілі чи булеві значення можна явно вставити у вихідний код із власним синтаксисом. Ваш інтерпретатор повинен припустити, що пробіг числових символів позначає ціле число (вам не потрібно реалізувати синтаксис, щоб явно вставити негативні цілі числа). Ваш перекладач також повинен припускати , що true
і false
позначені значення Boolean. Функції не можуть бути чітко визначені користувачем, і вони завжди повертатимуть одне значення (Список будь-якої довжини рахується як одне значення).
Функції
Для впровадження необхідні наступні функції, які знаходяться у форматі Функція , Артіті . Якщо Arity n
переходить зі знаком плюс, то це позначає n
або більше аргументів. Ви можете припустити, що всі аргументи, надані функції, є одного типу, якщо не вказано інше. Ви також можете припустити, що якщо для сертифікованого типу не вказано жодної поведінки, то ви можете припустити, що жоден аргумент цієї функції ніколи не буде такого типу. Аргументи будуть посилатися на наступну діаграму:
(func argument1 argument2 ... argumentn)
+ , 2+
- Якщо всі аргументи мають тип Integer , потрібно повернути суму аргументів
- Якщо всі аргументи мають список List , ви повинні повернути конкатенацію аргументів у порядку зростання (
arg1+arg2+ ...
) - Якщо всі аргументи мають тип булевого типу , ви повинні повернути логічну всю послідовність аргументів
(+ 1 2 3 4 5) -> 15
(+ (list 1 2) (list 3 4)) -> (list 1 2 3 4)
(+ true true true) -> true
- , 2+
- Якщо всі аргументи типу Integer , ви повинні повернути різницю аргументів (
arg1-arg2- ...
) - Якщо всі аргументи мають тип булевого типу , ви повинні повернути логічну Будь-яку з послідовностей аргументів
(- 8 4 3) -> 1
(- 0 123) -> -123
(- true false false true false) -> true
- Якщо всі аргументи типу Integer , ви повинні повернути різницю аргументів (
* , 2+
- Якщо всі аргументи мають тип Integer , потрібно повернути добуток аргументів
- Якщо один аргумент має тип List, а другий - тип Integer (ви можете припустити, що це будуть лише наведені аргументи), ви повинні повернути новий список з елементами
arg1
повторноarg2
. (* 1 2 3 4 5) -> 120
(* (list 1 2 3) 2) -> (list 1 2 3 1 2 3)
/ , 2+
- Якщо всі аргументи типу Integer , ви повинні повернути коефіцієнт аргументів (
arg/arg2/ ...
) (ви можете припустити, що ділення виконується послідовно, і що десяткова частина на кожному кроці усікається) - Якщо один аргумент має тип List, а другий має функцію типу , тоді ви повинні повернути отриманий список після того,
arg2
як буде відображено кожне значення (/ 100 10 3) -> 3
(/ (list 1 2 3) inc) -> (list 2 3 4)
- Якщо всі аргументи типу Integer , ви повинні повернути коефіцієнт аргументів (
% , 2
- Якщо всі аргументи мають тип Integer , ви повинні повернути модуль аргументів
(% 4 2) -> 0
= , 2+
- Якщо і тип, і значення всіх аргументів однакові, ви повинні повернути true. В іншому випадку поверніть хибне.
(= 0 0 0) -> true
(= 0 false (list)) -> false
список , 0+
- Ви повинні повернути список усіх аргументів, незалежно від типу. Якщо аргументів не наводиться, ви повинні повернути порожній список
(list 3 4 (list 5)) -> (list 3 4 (list 5))
вкл. , 1
- Якщо аргумент типу Integer , ви повинні повернути Integer, збільшений на одиницю
- Якщо аргумент типу List , ви повинні повернути список, повернутий за годинниковою стрілкою, одним обертанням
(inc 1) -> 2
(inc (list 1 2 3)) -> (list 3 1 2)
груд. , 1
- Якщо аргумент типу Integer , ви повинні повернути ціле число зменшене на одиницю
- Якщо аргумент типу List , ви повинні повернути список, повернутий проти годинникової стрілки, одним обертанням
(dec 1) -> 0
(dec (list 1 2 3)) -> (list 2 3 1)
якщо , 3
- Якщо дано три аргументи будь-якого типу: Якщо значення істини
arg1
є істинним, повернітьarg2
, інакше повернітьarg3
(if (not (list 1)) 8 false) -> false
- Якщо дано три аргументи будь-якого типу: Якщо значення істини
ні , 1
- Якщо вам дано аргумент будь-якого типу, якщо значення істинності
arg1
False, повернітьtrue
, інакше повернітьfalse
. (not (list)) -> true
- Якщо вам дано аргумент будь-якого типу, якщо значення істинності
len , 1
- Якщо вам дано аргумент типу List , поверніть довжину
arg1
(len (list 4 2 true (list 3) (list))) -> 5
- Якщо вам дано аргумент типу List , поверніть довжину
Таблиця істини:,
0, (list), false -> false
де (list)
позначається порожній список. Все інше є true
.
Ваш інтерпретатор може бути або повноцінною програмою, яка зчитує вхід джерела зі stdin або файлу, або функцією, яка приймає джерело як рядок і повертає вихідне значення.
Якщо вибирати перший, вихід для Integers - це просто числа, для Booleans є true
або false
, а для списків - це розділена пробілом послідовність значень, укладених у дужки (наприклад, (1 2 3 4 (5 6 7))
позначає (list 1 2 3 4 (list 5 6 7))
).
Якщо вибираєте останнє, значення повинно бути повернуто відповідним типом мови реалізації або, якщо подібного типу не існує, спеціальним типом. Списки можуть бути повернуті як масиви або вектори , якщо мова не має список типу, Booleans повинен бути повернутий в якості логічного типу в мові, або типу , якщо мова не підтримує їх.
Тестові справи
(list 1 2 3 (list 4 5 true)) -> (1 2 3 (4 5 true))
(/ 4000 (+ 1 2 3 4 (* 5 8))) -> 80
(+ (not (- (len (list 5 6 7)) (/ 10 3))) true) -> true
(if ( len (list ) ) 4 (if (+ (= 8 8 8) (not (list 4))) 8 5)) -> 5
Роз'яснення
- Ваш перекладач може мати справу з недійсним входом будь-яким обраним вами способом, але він не повинен викидати виняток (хоча він може надрукувати повідомлення про помилку та плавно вийти)
- Функції завжди оцінюють аргументи зліва направо
- Недійсний вхід - це будь-який вхід, який є синтаксично неправильним. Сюди входять, але не обмежуються ними, невідповідні дужки, поділ на нуль та частково застосовані функції (якщо не йдеться про бонус)
- Бо
=
якщо будь-яке з значень відрізняється або будь-який із типів відрізняється, повернітьсяfalse
Бонуси
- Оцінка * 0,8, якщо ви підтримуєте частково застосовані функції. Наприклад,
((+ 2) 3)
було б те саме(+ 2 3)
, але дозволяє такі речі, як(/ (list 1 2 3) (+ 2))
. Можна припустити, що функція частково застосовується, якщо вона отримує менше, ніж її мінімальна кількість аргументів - Оцінка * 0,85, якщо ви не оцінюєте аргументи, застосовані до них,
if
якщо вони не повернуться
Це код-гольф, тому перекладач з найнижчою кількістю байтів виграє!
(+ 3 (if false 5))
? Взагалі кажучи, що насправді "нічого не повертає"? Ви не вказали жодного типу одиниць, які підлягають відновленню
(+ bool bool...)
логічне І і (- bool bool...)
логічне АБО? Стандартне позначення кільця буде використовуватися +
для АБО і *
для І. 2. Чи "недійсний вхід" призначений для покриття випадків, (/ 2 0)
які є синтаксично правильними? 3. Бо =
, якщо значення не всі однакові, вони повинні повертатися false
? 4. Визначення not
виглядає як зворотне. 5. Що таке жетони? Ви говорите, що перекладач повинен працювати з додатковою пробілом, але ви не кажете, на який пробіл може покластися. Для складних питань, таких як цей, ви дійсно повинні використовувати пісочницю, щоб перевірити специфікацію.
((+ 2 3) 4)
дорівнює 9
чи помилка? Зокрема, для функцій var-arg не ясно, коли слід вважати програму частковою. Він стає ще більш каламутним з таких речей, як((if true (+ 2 3) (- 5)) 4)
(if (not (array 1)) 8 false) -> false
?