Track
/
Elixir
Elixir
/
Esercizi
/
Prendi un numero
Prendi un numero

Prendi un numero

Esercizio di apprendimento

Introduzione

Processi

In Elixir, tutto il codice viene eseguito all'interno di processi.

Per impostazione predefinita, una funzione viene eseguita nello stesso processo da cui è stata chiamata. Quando devi eseguire esplicitamente una certa funzione in un nuovo processo, usa spawn/1:

spawn(fn -> 2 + 2 end)
# => #PID<0.125.0>

spawn/1 crea un nuovo processo che esegue la funzione a zero argomenti indicata e restituisce un identificatore di processo (PID). Il nuovo processo rimane attivo fintanto che la funzione viene eseguita, poi termina silenziosamente.

I processi di Elixir non vanno confusi con i processi del sistema operativo. I processi di Elixir usano molta meno memoria e CPU. Va benissimo avere applicazioni Elixir che eseguono centinaia di processi Elixir.

Messaggi

I processi non condividono direttamente le informazioni tra loro. I processi inviano e ricevono messaggi per condividere dati.

Puoi inviare un messaggio a qualsiasi processo con send/2. Il primo argomento di send/2 è il PID del destinatario, il secondo è il messaggio.

Un messaggio può essere di qualsiasi tipo. Spesso è composto da atomi e tuple. Se vuoi ricevere una risposta, dovresti includere da qualche parte nel messaggio il PID del mittente. Puoi ottenere il PID del processo corrente con self().

send/2 non controlla se il messaggio è stato ricevuto dal destinatario, né se il destinatario è ancora attivo. Il messaggio finisce nella casella di posta del destinatario e viene letto solo se e quando il destinatario chiede esplicitamente di ricevere messaggi.

Un messaggio può essere letto da una casella di posta usando la macro receive/1. Accetta un blocco do che può eseguire il pattern matching sui messaggi.

receive do
  {:ping, sender_pid} -> send(sender_pid, :pong)
  :do_nothing -> nil
end

receive/1 prende un solo messaggio dalla casella di posta che corrisponde a uno qualsiasi dei pattern indicati ed esegue l'espressione indicata per quel pattern. Se nella casella di posta non ci sono messaggi, o nessuno dei messaggi corrisponde a uno dei pattern, receive/1 aspetta che ne arrivi uno.

Ciclo di ricezione

Se vuoi ricevere più di un messaggio, devi chiamare receive/1 in modo ricorsivo. È uno schema comune implementare una funzione ricorsiva, ad esempio chiamata loop, che chiama receive/1, fa qualcosa con il messaggio e poi chiama se stessa per attendere altri messaggi. Se devi portare con te uno stato da una chiamata a receive/1 a un'altra, puoi farlo passando un argomento a quella funzione loop.

I PID

Gli identificatori di processo sono un tipo di dato a sé. Fungono da indirizzi della casella di posta: se hai il PID di un processo, puoi inviargli un messaggio. I PID vengono di solito creati indirettamente, come valore restituito dalle funzioni che creano nuovi processi, come spawn.

Istruzioni

Stai scrivendo un sistema embedded per una macchina che distribuisce numeri. È un modello molto semplice. Può distribuire numeri consecutivi e riportare qual è stato l'ultimo numero distribuito.

1. Avvia la macchina

Implementa la funzione start/0. Deve avviare un nuovo processo e restituire il PID del processo. Il nuovo processo non deve ancora fare nulla.

TakeANumber.start()
# => #PID<0.138.0>

Nota che ogni volta che esegui questo codice, il PID può essere diverso.

2. Riporta lo stato della macchina

Modifica la macchina in modo che il processo appena avviato sia pronto a ricevere messaggi (avvia un ciclo di ricezione) con uno stato iniziale di 0. Deve essere in grado di ricevere messaggi {:report_state, sender_pid}. In risposta a questi messaggi, deve inviare il suo stato attuale (il numero dell'ultimo biglietto distribuito) a sender_pid e poi aspettare altri messaggi.

machine_pid = TakeANumber.start()

# a client sending a message to the machine
send(machine_pid, {:report_state, self()})

# a client receiving a message from the machine
receive do
  msg -> msg
end

# => 0

3. Distribuisci i numeri

Modifica la macchina in modo che possa ricevere messaggi {:take_a_number, sender_pid}. Deve aumentare il suo stato di 1, inviare il nuovo stato a sender_pid e poi aspettare altri messaggi.

machine_pid = TakeANumber.start()

# a client sending a message to the machine
send(machine_pid, {:take_a_number, self()})

# a client receiving a message from the machine
receive do
  msg -> msg
end

# => 1

4. Ferma la macchina

Modifica la macchina in modo che possa ricevere un messaggio :stop. Deve smettere di aspettare altri messaggi.

5. Ignora i messaggi inaspettati

Modifica la macchina in modo che, quando riceve un messaggio inaspettato, lo ignori e continui ad aspettare altri messaggi.

Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
Elixir Exercism

Vuoi iniziare Prendi un numero?

Iscriviti a Exercism per imparare e padroneggiare Elixir con 58 concetti168 esercizi e il mentoring di persone reali, tutto gratis.