Trilhas
/
jq
jq
/
Exercícios
/
Carrinho de controle remoto
Carrinho de controle remoto

Carrinho de controle remoto

Exercício de aprendizagem

Introdução

Funções

Você pode definir suas próprias funções personalizadas em jq para encapsular a lógica que precisar. Funções funcionam igual às funções nativas: elas recebem uma entrada e emitem zero, um ou mais resultados.

Definindo uma função

Você pode definir uma função jq usando a seguinte sintaxe:

# no arguments
def funcname: expression;

# or with arguments
def funcname(args): expression;
  • começa com a palavra-chave def,
  • dois-pontos antes do corpo da função,
  • o corpo consiste em uma única expressão,
  • termina com ponto e vírgula,
  • como no resto da sintaxe do jq, você pode usar espaços em branco à vontade para facilitar a leitura.

Onde colocar funções

Funções precisam ser definidas antes de serem usadas: isto é um erro:

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

Isso significa que você precisa colocar as funções no topo do seu código jq, antes da expressão "principal".

Funções aninhadas

Funções podem ser aninhadas:

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

Aqui, a função B só é visível no corpo de A.

Escopo

Uma função introduz um novo escopo para variáveis e funções aninhadas.

Argumentos

Os argumentos de uma função são separados por ponto e vírgula, não por vírgulas. Por exemplo, uma função que recebe um número, e depois soma um número e multiplica por um número:

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

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

Ponto e vírgula é necessário porque a vírgula já tem uma finalidade no jq: um operador que junta fluxos.

Usar uma vírgula em vez de ponto e vírgula vai tentar fazer duas chamadas a uma função add_mul de 1 argumento, que não existe e, portanto, vai falhar na primeira tentativa de chamada:

10 | add_mul(5, 4)
# error: add_mul/1 is not defined
Argumentos são expressões

Os argumentos de uma função são filtros, não valores. Nesse sentido, eles funcionam como o que outras linguagens descrevem como callbacks:

Usando a função add_mul como exemplo:

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

O que está acontecendo aqui?

  • o argumento adder recebe a expressão . + 5
    • quando a função faz . + adder, isso vira . + . + 5
    • isso resulta em 25, já que . == 10
  • da mesma forma, o argumento multiplier é a expressão . - 2
    • isso resulta em 8
    • então o resultado é 25 * 8 == 200
Argumentos como valores

Às vezes você vai querer "materializar" um argumento em uma variável:

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

Existe uma forma abreviada para isso:

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

Vale notar que isso é apenas "açúcar sintático": o nome arg sem $ continua no escopo dentro da função.

Aridade

Funções têm uma aridade, ou seja, o número de argumentos que recebem.

Funções podem usar o mesmo nome com aridades diferentes. A função nativa range demonstra isso: range/1, range/2 e range/3 coexistem.

Isso pode ser útil para definir funções recursivas que carregam estado por meio de argumentos. Por exemplo, map poderia ser implementado assim:

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]

Recursão

O jq faz otimização de chamadas de cauda, mas apenas para funções de aridade 0.

Módulos

Um módulo jq é um arquivo contendo apenas funções. Módulos são incluídos em um programa jq com os comandos include ou import.

Instruções

Neste exercício, você vai brincar com um carro de controle remoto, para o qual finalmente juntou dinheiro suficiente para comprar.

Os carros começam com a bateria cheia (100%). Cada vez que você dirige o carro usando o controle remoto, ele percorre 20 metros e gasta um por cento da bateria. O apelido do carro só é conhecido quando ele é criado.

O carro de controle remoto tem um display de LED sofisticado que mostra duas informações:

  • A distância total percorrida, exibida como: "<METERS> meters".
  • A carga restante da bateria, exibida como: "Battery at <PERCENTAGE>%".

Se a bateria estiver em 0%, você não pode mais dirigir o carro e o display da bateria vai mostrar "Battery empty".

1. Crie um carro de controle remoto novinho em folha

Implemente a função new_remote_control_car/0 para retornar um objeto de carro de controle remoto novinho em folha:

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

2. Crie um carro de controle remoto novinho em folha com um apelido

Implemente a função new_remote_control_car/1 para retornar um objeto de carro de controle remoto novinho em folha com um apelido fornecido:

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

3. Exiba a distância

Implemente a função display_distance/0 que recebe um objeto de carro como entrada e retorna a string de distância exibida no display de LED:

new_remote_control_car | display_distance
# => "0 meters"

4. Exiba a porcentagem da bateria

Implemente a função display_battery/0 que recebe um objeto de carro como entrada e retorna a string da porcentagem da bateria exibida no display de LED:

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

Se a bateria estiver em 0%, o display da bateria vai mostrar "Battery empty".

5. Dirigir altera a bateria e a distância percorrida

Implemente a função drive/0 que:

  • recebe um objeto de carro como entrada
  • aumenta em 20 o número de metros percorridos
  • gasta 1% da bateria
  • retorna o objeto de carro modificado
new_remote_control_car("Red") | drive
# => {
#      "battery_percentage": 99,
#      "distance_driven_in_meters": 20,
#      "nickname": "Red"
#    }

6. Lide com a direção com a bateria descarregada

Atualize a função drive/0 para não aumentar a distância percorrida nem diminuir a porcentagem da bateria quando a bateria estiver descarregada (em 0%):

{
  battery_percentage: 0,
  distance_driven_in_meters: 2000,
  nickname: "Red"
} | drive
# => {
#      "battery_percentage": 0,
#      "distance_driven_in_meters": 2000,
#      "nickname": "Red"
#    }
Editar via GitHub O link abre em uma nova janela ou aba
jq Exercism

Tudo pronto para começar Carrinho de controle remoto?

Crie sua conta no Exercism para aprender e dominar jq com 12 conceitos75 exercícios e mentoria humana de verdade, tudo de graça.