트랙
/
jq
jq
/
연습 문제
/
무선 조종 자동차
무선 조종 자동차

무선 조종 자동차

학습 연습 문제

소개

함수

jq에서는 필요한 로직을 하나로 묶기 위해 사용자 정의 함수를 직접 정의할 수 있어요. _함수_는 내장 함수와 똑같이 동작해요. 입력을 받아서 0개, 1개 또는 그 이상의 출력을 내보내요.

함수 정의하기

다음 문법으로 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에서 스트림을 이어 붙이는 연산자로 쓰이고 있기 때문이에요.

세미콜론 대신 쉼표를 쓰면 인자가 1개인 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가 돼요
    • . == 10이므로 이는 25로 평가돼요
  • 마찬가지로 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 모듈은 함수만 담고 있는 파일이에요. 모듈은 include나 import 명령으로 jq 프로그램에 포함시켜요.

지침

이번 연습 문제에서는 그동안 돈을 모아서 드디어 장만한 무선 조종 자동차를 가지고 놀아볼 거예요.

자동차는 배터리가 가득 찬(100%) 상태로 시작해요. 리모컨으로 자동차를 운전할 때마다 20미터를 이동하고 배터리를 1퍼센트 소모해요. 자동차의 별명은 자동차가 만들어지기 전까지는 알 수 없어요.

무선 조종 자동차에는 두 가지 정보를 보여주는 멋진 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. 거리 표시하기

자동차 객체를 입력으로 받아 LED 디스플레이에 표시되는 거리 문자열을 출력하는 display_distance/0 함수를 구현해요:

new_remote_control_car | display_distance
# => "0 meters"

4. 배터리 잔량 표시하기

자동차 객체를 입력으로 받아 LED 디스플레이에 표시되는 배터리 잔량 문자열을 출력하는 display_battery/0 함수를 구현해요:

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. 방전된 배터리로 운전하는 경우 처리하기

배터리가 방전된(0%) 경우에는 이동 거리도 늘리지 않고 배터리 잔량도 줄이지 않도록 drive/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개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.