Rutas
/
jq
jq
/
Ejercicios
/
Coche teledirigido
Coche teledirigido

Coche teledirigido

Ejercicio de aprendizaje

Introducción

Funciones

Puedes definir tus propias funciones personalizadas en jq para encapsular la lógica que necesites. Las funciones se comportan igual que las integradas: reciben una entrada y emiten cero, una o más salidas.

Definir una función

Puedes definir una función de jq con la siguiente sintaxis:

# no arguments
def funcname: expression;

# or with arguments
def funcname(args): expression;
  • empieza por la palabra clave def,
  • lleva dos puntos antes del cuerpo de la función,
  • el cuerpo consta de una única expresión,
  • termina con un punto y coma,
  • igual que en el resto de la sintaxis de jq, puedes usar espacios en blanco arbitrarios para que sea más legible.

Dónde colocar las funciones

Las funciones deben definirse antes de usarse: esto es un error:

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

Esto implica que tienes que colocar las funciones al principio de tu código jq, antes de la expresión «principal».

Funciones anidadas

Las funciones se pueden anidar:

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

Aquí, la función B solo es visible en el cuerpo de A.

Scope

Una función introduce un nuevo scope para las variables y las funciones anidadas.

Argumentos

Los argumentos de las funciones se separan con puntos y comas, no con comas. Por ejemplo, una función que recibe un número y, a continuación, le suma un número y multiplica por otro número:

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

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

Los puntos y comas son necesarios porque la coma ya tiene un propósito en jq: es un operador que une flujos.

Si usas una coma en lugar de un punto y coma, se intentará hacer dos llamadas a una función add_mul de 1 argumento, que no existe y, por lo tanto, fallará en la primera llamada:

10 | add_mul(5, 4)
# error: add_mul/1 is not defined
Los argumentos son expresiones

Los argumentos de las funciones son filtros, no valores. En este sentido, se comportan como lo que otros lenguajes describen como callbacks:

Tomando como ejemplo la función add_mul:

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

¿Qué está pasando aquí?

  • el argumento adder recibe la expresión . + 5
    • cuando la función hace . + adder, eso se convierte en . + . + 5
    • que se evalúa como 25, ya que . == 10
  • de forma parecida, el argumento multiplier es la expresión . - 2
    • que se evalúa como 8
    • y entonces el resultado es 25 * 8 == 200
Argumentos como valores

A veces querrás «materializar» un argumento en una variable:

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

Existe una forma abreviada de hacer esto:

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

Ten en cuenta que esto no es más que «azúcar sintáctico»: el nombre arg sin $ sigue estando en el scope de la función.

Aridad

Las funciones tienen una aridad: el número de argumentos que reciben.

Las funciones pueden usar el mismo nombre con aridades distintas. La función integrada range lo demuestra: range/1, range/2 y range/3 coexisten.

Esto puede ser útil para definir funciones recursivas que mantienen su estado a través de los argumentos. Por ejemplo, map podría implementarse así:

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]

Recursión

jq aplica la optimización de llamadas de cola, pero solo en funciones de aridad 0.

Módulos

Un módulo de jq es un archivo que solo contiene funciones. Los módulos se incluyen en un programa de jq con los comandos include o import.

Instrucciones

En este ejercicio vas a jugar con un coche teledirigido, para el que por fin has ahorrado suficiente dinero para comprarlo.

Los coches empiezan con la batería llena (100%). Cada vez que conduces el coche con el mando a distancia, recorre 20 metros y consume un uno por ciento de la batería. El apodo del coche no se conoce hasta que se crea.

El coche teledirigido tiene una pantalla LED llamativa que muestra dos datos:

  • La distancia total que ha recorrido, mostrada como: "<METERS> meters".
  • La carga restante de la batería, mostrada como: "Battery at <PERCENTAGE>%".

Si la batería está al 0%, ya no puedes conducir el coche y la pantalla de la batería mostrará "Battery empty".

1. Crea un coche teledirigido completamente nuevo

Implementa la función new_remote_control_car/0 para que devuelva un objeto de coche teledirigido completamente nuevo:

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

2. Crea un coche teledirigido completamente nuevo con un apodo

Implementa la función new_remote_control_car/1 para que devuelva un objeto de coche teledirigido completamente nuevo con un apodo proporcionado:

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

3. Muestra la distancia

Implementa la función display_distance/0, que toma un objeto de coche como entrada y devuelve el string de la distancia tal y como se muestra en la pantalla LED:

new_remote_control_car | display_distance
# => "0 meters"

4. Muestra el porcentaje de batería

Implementa la función display_battery/0, que toma un objeto de coche como entrada y devuelve el string del porcentaje de batería tal y como se muestra en la pantalla LED:

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

Si la batería está al 0%, la pantalla de la batería mostrará «Battery empty».

5. Conducir cambia la batería y la distancia recorrida

Implementa la función drive/0 que:

  • toma un objeto de coche como entrada
  • incrementa en 20 el número de metros recorridos
  • consume un 1% de la batería
  • devuelve el objeto de coche modificado
new_remote_control_car("Red") | drive
# => {
#      "battery_percentage": 99,
#      "distance_driven_in_meters": 20,
#      "nickname": "Red"
#    }

6. Ten en cuenta la conducción con la batería agotada

Actualiza la función drive/0 para que no aumente la distancia recorrida ni disminuya el porcentaje de batería cuando la batería está agotada (al 0%):

{
  battery_percentage: 0,
  distance_driven_in_meters: 2000,
  nickname: "Red"
} | drive
# => {
#      "battery_percentage": 0,
#      "distance_driven_in_meters": 2000,
#      "nickname": "Red"
#    }
Editar en GitHub El enlace se abre en una ventana o pestaña nueva
jq Exercism

¿Listo para empezar Coche teledirigido?

Regístrate en Exercism para aprender y dominar jq con 12 conceptos75 ejercicios y mentoría humana real, todo gratis.