Track
/
jq
jq
/
Esercizi
/
Auto radiocomandata
Auto radiocomandata

Auto radiocomandata

Esercizio di apprendimento

Introduzione

Le funzioni

Puoi definire le tue funzioni personalizzate in jq per incapsulare la logica di cui hai bisogno. Le funzioni si comportano esattamente come i builtin: ricevono un input ed emettono zero, uno o più output.

Definire una funzione

Puoi definire una funzione jq con la seguente sintassi:

# no arguments
def funcname: expression;

# or with arguments
def funcname(args): expression;
  • inizia con la parola chiave def,
  • i due punti prima del corpo della funzione,
  • il corpo è costituito da una sola espressione,
  • termina con un punto e virgola,
  • come nel resto della sintassi di jq, puoi usare spazi bianchi arbitrari per migliorare la leggibilità.

Dove definire le funzioni

Le funzioni devono essere definite prima di essere usate: questo è un errore:

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

Di conseguenza, devi collocare le funzioni all'inizio del tuo codice jq, prima dell'espressione «principale».

Funzioni annidate

Le funzioni possono essere annidate:

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

Qui, la funzione B è visibile solo nel corpo di A.

Scope

Una funzione introduce un nuovo scope per le variabili e le funzioni annidate.

Gli argomenti

Gli argomenti di una funzione sono separati da punti e virgola, non da virgole. Per esempio, una funzione che riceve un numero, poi aggiunge un numero e moltiplica per un numero:

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

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

I punti e virgola sono necessari perché la virgola ha già uno scopo in jq: è un operatore che unisce gli stream.

Usare una virgola al posto di un punto e virgola tenta di fare due chiamate a una funzione add_mul a un argomento, che non esiste e quindi fallirà al primo tentativo di chiamata:

10 | add_mul(5, 4)
# error: add_mul/1 is not defined
Gli argomenti sono espressioni

Gli argomenti di una funzione sono filtri, non valori. In questo senso, si comportano come quello che altri linguaggi chiamano callback:

Prendiamo come esempio la funzione add_mul:

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

Cosa succede qui?

  • l'argomento adder riceve l'espressione . + 5
    • quando la funzione esegue . + adder, questo diventa . + . + 5
    • il risultato è 25, dato che . == 10
  • allo stesso modo, l'argomento multiplier è l'espressione . - 2
    • il risultato è 8
    • quindi il risultato è 25 * 8 == 200
Gli argomenti come valori

A volte ti servirà «materializzare» un argomento in una variabile:

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

Esiste una sintassi abbreviata per farlo:

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

Tieni presente che si tratta solo di «zucchero sintattico»: il nome arg senza $ è comunque nello scope della funzione.

Arietà

Le funzioni hanno un'arietà: il numero di argomenti che accettano.

Le funzioni possono usare lo stesso nome con arietà diverse. La funzione builtin range lo dimostra: range/1, range/2 e range/3 coesistono tutte.

Questo può essere utile per definire funzioni ricorsive che trasportano stato tramite argomenti. Per esempio, map potrebbe essere implementata così:

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]

La ricorsione

jq esegue l'ottimizzazione delle chiamate in coda, ma solo per le funzioni con arietà 0.

I moduli

Un modulo jq è un file che contiene solo funzioni. I moduli si includono in un programma jq con i comandi include o import.

Istruzioni

In questo esercizio giocherai con un'auto radiocomandata, che finalmente hai risparmiato abbastanza soldi per comprare.

Le auto partono con la batteria completamente carica (100%). Ogni volta che guidi l'auto con il radiocomando, percorre 20 metri e consuma l'uno percento della batteria. Il soprannome dell'auto non è noto finché non viene creata.

L'auto radiocomandata ha un elegante display a LED che mostra due informazioni:

  • La distanza totale percorsa, visualizzata come: "<METERS> meters".
  • La carica residua della batteria, visualizzata come: "Battery at <PERCENTAGE>%".

Se la batteria è allo 0%, non puoi più guidare l'auto e il display della batteria mostrerà "Battery empty".

1. Crea un'auto radiocomandata nuova di zecca

Implementa la funzione new_remote_control_car/0 in modo che restituisca un oggetto auto radiocomandata nuovo di zecca:

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

2. Crea un'auto radiocomandata nuova di zecca con un soprannome

Implementa la funzione new_remote_control_car/1 in modo che restituisca un oggetto auto radiocomandata nuovo di zecca con un soprannome fornito:

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

3. Visualizza la distanza

Implementa la funzione display_distance/0 che prende in input un oggetto auto e restituisce la stringa della distanza così come viene visualizzata sul display a LED:

new_remote_control_car | display_distance
# => "0 meters"

4. Visualizza la percentuale della batteria

Implementa la funzione display_battery/0 che prende in input un oggetto auto e restituisce la stringa della percentuale della batteria così come viene visualizzata sul display a LED:

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

Se la batteria è allo 0%, il display della batteria mostrerà "Battery empty".

5. Guidare modifica la batteria e la distanza percorsa

Implementa la funzione drive/0 che:

  • prende in input un oggetto auto
  • aumenta di 20 il numero di metri percorsi
  • consuma l'1% della batteria
  • restituisce l'oggetto auto modificato
new_remote_control_car("Red") | drive
# => {
#      "battery_percentage": 99,
#      "distance_driven_in_meters": 20,
#      "nickname": "Red"
#    }

6. Gestisci la guida con la batteria scarica

Aggiorna la funzione drive/0 in modo che non aumenti la distanza percorsa né diminuisca la percentuale della batteria quando la batteria è scarica (allo 0%):

{
  battery_percentage: 0,
  distance_driven_in_meters: 2000,
  nickname: "Red"
} | drive
# => {
#      "battery_percentage": 0,
#      "distance_driven_in_meters": 2000,
#      "nickname": "Red"
#    }
Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
jq Exercism

Vuoi iniziare Auto radiocomandata?

Iscriviti a Exercism per imparare e padroneggiare jq con 12 concetti75 esercizi e il mentoring di persone reali, tutto gratis.