Journal Portage de TapTempo en Elixir

Posté par . Licence CC by-sa.
Tags :
16
10
mar.
2018

Salut à tous!

Voici un portage très simple et assez naif de TapTempo en Elixir. Elixir est un langage fonctionnel exécuté par la machine virtuelle d'Erlang. Il comprend des features intéressantes de flow programming, pattern matching etc. Les variables sont immuables de base et le langage ne comprend pas d'instructions pour boucler (le for est utilisé uniquement pour des compréhensions) et incite donc a utiliser la récursion, plus fonctionnelle.

Le port lui-même est assez naïf mais fonctionne bien. Notez la compacité du code:

defmodule Taptempo do
  def get_input do
    get_input("", 0)
  end

  def get_input("q", count) do
    {count, Time.utc_now()}
  end

  def get_input(_, count) do
    IO.read(1)
    |> String.trim
    |> get_input(count + 1)
  end

  def calc_tempo({taps, end_time}, start_time) do
    time_diff = Time.diff(end_time, start_time, :microsecond)
    taps / (time_diff / 1000000) * 60
  end

  def print_tempo(tempo) do
    IO.puts("Tempo: #{:erlang.float_to_binary(tempo, [decimals: 2])} bpm")
  end

  def main do
    IO.puts("Appuyer sur la touche entrée en cadence (q pour quitter).")
    start_time = Time.utc_now()
    get_input()
      |> calc_tempo(start_time)
      |> print_tempo()
  end
end

Taptempo.main()

Notez l'utilisation du pattern matching sur la fonction get_input. Le pattern matching permet d'éxécuter des variations de la même fonction par rapport aux arguments qui sont passés. Elixir va chercher la fonction qui convient aux arguments donnés de haut en bas, d'où la définition du get_input générique en dernier.

Le symbole |> permet d'utiliser du flow programming en passant le retour d'une fonction en tant que premier argument pour la fonction suivante, un peu comme une pipe unix. Le flow dans main pourrait donc s'écrire comme suit:

taps_info = get_input()
tempo = calc_tempo(taps_info)
print_tempo(tempo)

Ou aussi:

print_tempo(calc_tempo(get_input)))

Enfin, la fonction get_input retourne un tuple, dénoté comme suit: {count, Time.utc_now()}. Ce tuple est ensuite pattern matché directement par la fonction calc_tempo, comme suit:

  def calc_tempo({taps, end_time}, start_time) do
    ...
  end

Si vous souhaitez exécuter le code, copiez-collez dans un fichier taptempo.ex puis exécutez avec elixir taptempo.ex.

  • # Elixir

    Posté par (page perso) . Évalué à 3.

    Sympa cette version !
    Je ne vois pas où se situe la boucle qui permet d'afficher les tempi successifs comme dans l'original. Est-elle cachée dans les appels récursifs ou il n'y a qu'un seul tempo qui est calculé lorsqu'on entre la lettre “q” ?

    • [^] # Re: Elixir

      Posté par . Évalué à 2. Dernière modification le 11/03/18 à 14:47.

      Apparemment le programme n’affiche le résultat qu’une fois la touche "q" appuyée effectivement, car la fonction get_input se rappelle elle même jusqu’à trouver "q" en paramètre, et à ce moment là le compteur va être retourné avec le temps.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.