Треки
/
jq
jq
/
Вправи
/
Машинка на радіокеруванні
Машинка на радіокеруванні

Машинка на радіокеруванні

Навчальна вправа

Вступ

Функції

Ми можемо визначати власні функції у jq, щоб інкапсулювати будь-яку логіку, яка нам потрібна. Функції поводяться так само, як вбудовані: вони приймають вхідні дані й видають нуль, одні або кілька вихідних даних.

Визначення функції

Ми можемо визначити функцію jq за таким синтаксисом:

# no arguments
def funcname: expression;

# or with arguments
def funcname(args): expression;
  • починається з ключового слова def,
  • двокрапка перед тілом функції,
  • тіло складається з одного виразу,
  • закінчується крапкою з комою,
  • як і решта синтаксису jq, ми можемо використовувати довільні пробіли для читабельності.

Де розміщувати функції

Функції потрібно визначити до того, як ми їх використаємо: ось це помилка:

def A: B(10);
def B(n): n + 1;
A
# => error: B/1 is not defined

Це означає, що функції треба розмістити на початку нашого коду jq, перед «головним» виразом.

Вкладені функції

Функції можна вкладати:

def A:
    def B(n): n + 1;
    B(10)
    ;
A
# => 11

Тут функція B видима лише в тілі A.

Область видимості

Функція вводить нову область видимості для змінних і вкладених функцій.

Аргументи

Аргументи функції розділяються крапками з комою, а не комами. Наприклад, функція, яка приймає число, а потім додає число і множить на число:

def add_mul(adder; multiplier): (. + adder) * multiplier;

10 | add_mul(5; 4)    # => 60
Note

Крапки з комою потрібні, бо кома в jq вже має своє призначення: це оператор, який зʼєднує потоки.

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

10 | add_mul(5, 4)
# error: add_mul/1 is not defined
Аргументи - це вирази

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

Візьмімо функцію add_mul як приклад:

10 | add_mul(. + 5; . - 2)    # => 200

Що тут відбувається?

  • аргумент adder отримує вираз . + 5
    • коли функція виконує . + adder, це стає . + . + 5
    • це дає 25, оскільки . == 10
  • так само аргумент multiplier - це вираз . - 2
    • це дає 8
    • тоді результат - 25 * 8 == 200
Аргументи як значення

Іноді нам захочеться «матеріалізувати» аргумент у змінну:

def my_func(arg):
    arg as $arg
    | other stuff ...
;

Для цього є скорочений запис:

def my_func($arg):
    other stuff ...
;

Зауважмо, що це лише «синтаксичний цукор»: імʼя arg без $ усе ще перебуває в області видимості функції.

Арність

Функції мають арність, тобто кількість аргументів, які вони приймають.

Функції можуть використовувати однакове імʼя з різною арністю. Вбудована функція range демонструє це: range/1, range/2 і range/3 співіснують.

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

def my_map($accumulator; func):
    if length == 0
        then $accumulator
        else first as $elem | .[1:] | my_map($accumulator + [$elem | func]; func)
    end
    ;

def my_map(func):
    my_map([]; func)
    ;

[1, 2, 3, 4] | my_map(. * 10)   # => [10, 20, 30, 40]

Рекурсія

jq виконує оптимізацію хвостових викликів, але лише для функцій з арністю 0.

Модулі

Модуль jq - це файл, що містить лише функції. Модулі підключаються до програми jq командами include або import.

Вказівки

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

Машинки починають роботу з повністю зарядженими (100%) акумуляторами. Щоразу, коли ми керуємо машинкою за допомогою пульта, вона проїжджає 20 метрів і витрачає один відсоток заряду акумулятора. Прізвисько машинки невідоме, доки її не створено.

Радіокерована машинка має вигадливий LED-дисплей, який показує дві частини інформації:

  • Загальна відстань, яку вона проїхала, показана як: "<METERS> meters".
  • Залишок заряду акумулятора, показаний як: "Battery at <PERCENTAGE>%".

Якщо заряд акумулятора становить 0%, ми більше не можемо керувати машинкою, і дисплей заряду показуватиме "Battery empty".

1. Створіть цілком нову радіокеровану машинку

Реалізуйте функцію new_remote_control_car/0, яка повертає цілком новий обʼєкт радіокерованої машинки:

new_remote_control_car
# => {
#      "battery_percentage": 100,
#      "distance_driven_in_meters": 0,
#      "nickname": null
#    }

2. Створіть цілком нову радіокеровану машинку з прізвиськом

Реалізуйте функцію new_remote_control_car/1, яка повертає цілком новий обʼєкт радіокерованої машинки із заданим прізвиськом:

new_remote_control_car("Blue")
# => {
#      "battery_percentage": 100,
#      "distance_driven_in_meters": 0,
#      "nickname": "Blue"
#    }

3. Покажіть відстань

Реалізуйте функцію display_distance/0, яка приймає обʼєкт машинки як вхідні дані та повертає рядок тексту (англ. string) з відстанню, як на LED-дисплеї:

new_remote_control_car | display_distance
# => "0 meters"

4. Покажіть відсоток заряду акумулятора

Реалізуйте функцію display_battery/0, яка приймає обʼєкт машинки як вхідні дані та повертає рядок тексту із відсотком заряду акумулятора, як на LED-дисплеї:

new_remote_control_car | display_battery
# => "Battery at 100%"

Якщо заряд акумулятора становить 0%, дисплей заряду показуватиме "Battery empty".

5. Керування змінює заряд акумулятора і пройдену відстань

Реалізуйте функцію drive/0, яка:

  • приймає обʼєкт машинки як вхідні дані
  • збільшує кількість пройдених метрів на 20
  • витрачає 1% заряду акумулятора
  • повертає змінений обʼєкт машинки
new_remote_control_car("Red") | drive
# => {
#      "battery_percentage": 99,
#      "distance_driven_in_meters": 20,
#      "nickname": "Red"
#    }

6. Врахуйте керування з розрядженим акумулятором

Оновіть функцію drive/0, щоб вона не збільшувала пройдену відстань і не зменшувала відсоток заряду акумулятора, коли акумулятор розряджений (0%):

{
  battery_percentage: 0,
  distance_driven_in_meters: 2000,
  nickname: "Red"
} | drive
# => {
#      "battery_percentage": 0,
#      "distance_driven_in_meters": 2000,
#      "nickname": "Red"
#    }
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
jq Exercism

Час розпочати Машинка на радіокеруванні?

Зареєструйтеся на Exercism, щоб вивчати й опановувати jq, а також 12 концепцій75 вправ та справжнє наставництво від людей, і все це безкоштовно.