Journal Portage de TapTempo en Perl6

Posté par (page perso) . Licence CC by-sa.
Tags :
23
1
mar.
2018

Bonjour à tous,
Suite aux portages de TapTempo en divers langages (Rust, Ada, Javascript, Perl (5.10), Python (2.7), bash), je me suis chargé de traduire cet outil en PERL6 parce que c'est quand même plus mignon à regarder.

J'ai essayé de respecter l'esprit de TapTempo à la lettre, en répliquant les fonctionnalités & options présentées dans le journal de mfz. De ce fait, j'ai adopté la même approche KISS tout en poussant le bouchon un peu plus loin puisque le script ne comporte aucune dépendance, même pas pour gérer le terminal. Il devrait donc fonctionner directement quelque soit la plateforme, pour peu qu'elle dispose d'un moteur PERL6.

Voici les quelques différences qui existent entre le TapTempo original et ce portage en PERL6 :
- Ce portage n'est pas internationalisé (la flemme me poursuit)
- Pour quitter le script, il faut appuyer sur q et entrée (ce n'était pas clairement spécifié dans le journal de mfz)
- Le code-source n'est hébergé qu'ici même
- Le code-source du script est en Unicode

Pour résumer, vous pouvez faire un simple copier/coller du code source ci-dessous dans un fichier texte (encodé en Unicode sinon ça ne marchera pas) pour le tester directement.

Les langues de la famille PERL ont souvent mauvaise réputation auprès des informaticiens, d'aucuns prétendent que ce sont des langues obscures, illisibles voir oubliées de tous, j'espère que la limpidité et la compacité du code source de ce script vous prouvera le contraire en moins de temps qu'il ne faut pour le lire.

Quoi qu'il en soit, vous retrouverez dans ce script quelques fonctionnalités intéressantes de PERL6, n'hésitez-pas à partir à la découverte des innombrables possibilités de cette fantastique langue de programmation, personnellement j'en suis resté bouche bée quand j'ai parcouru la documentation.

sub MAIN (
    Int :$precision? = 0,
    Int :$reset-time? = 5,
    Int :$sample-size? = 5,
    Bool :h(:$help)? = False,
    Bool :v(:$version)? = False
    )
    {
    say "Tap Tempo version 0.0 - Glaeken, licence GPL-3.0+" if $version;
    say q|  -h, --help            affiche ce message d'aide
  -p, --precision       changer le nombre de décimale du tempo à afficher
                        la valeur par défaut est 0 décimales, le max est 5 décimales
  -r, --reset-time      changer le temps en seconde de remise à zéro du calcul
                        la valeur par défaut est 5 secondes
  -s, --sample-size     changer le nombre d'échantillons nécessaires au calcul du tempo
                        la valeur par défaut est 5 échantillons
  -v, --version         afficher la version                    | if $help;
    exit if $version;
    exit if $help;
    exit if $precision < 0;
    exit if $precision > 5;
    exit if $sample-size < 2;
    exit if $reset-time < 0;
    my Int $Itérateur = 1;
    my @Dates;
    my $Rythme = prompt "Appuyer sur la touche entrée en cadence (q pour quitter).";
    exit if $Rythme eq 'q';
    @Dates.push:  DateTime.new(now);
    say "[Appuyer encore sur la touche entrée pour lancer le calcul du tempo...]";
    while True {
        $Rythme=prompt;
        my $Maintenant = DateTime.new(now);
        exit if $Rythme eq 'q';
        if $Maintenant - @Dates[$Itérateur-1] > $reset-time {
            while @Dates.elems {@Dates.shift}
            @Dates.push: $Maintenant;
            $Itérateur=1;
        } else {
            if $Itérateur < $sample-size {
                $Itérateur++;
                @Dates.push: $Maintenant;
            } else {
                @Dates.shift;
                @Dates.push: $Maintenant;
            }
            if @Dates[ @Dates.elems - 1 ] == @Dates[ 0 ] {
                say "Tempo : ∞";
            } else {
                $Rythme = @Dates.elems/(@Dates[@Dates.elems-1]-@Dates[0])* 60;
                if $precision == 0 {
                    say "Tempo : " ~ sprintf "%u bpm", $Rythme;
                } else {
                    say "Tempo : " ~ sprintf '%.' ~ $precision ~ 'f', $Rythme;
                }
            }
        }
    }
}

Petit détail, je n'ai pas pu m'empêcher de tester le cas pour lequel la durée entre deux frappes de la touche entrée était nulle, auquel cas le script vous répondra que le Tempo est infini.

N'hésitez-pas à tester et à envoyer vos remarques ou commentaires constructifs, il s'agit de mon premier journal sur LinuxFr.

  • # À quand le brainfuck

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

    J'attends avec impatience le portage de TapTempo en brainfuck et en whitespace ;)

  • # L'infini

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

    Merci pour ce portage qui tente de reproduire l'original au plus près !

    Je vois que tu as géré le cas où les deux dates sont similaires en affichant "Tempo : ∞". Bonne idée, même si c'est peu probable d'arriver il faut que je le rajoute :-)

    Petite question : les lignes "exit if $precision < 0;" font que le programme sort si les valeurs sont hors bornes ? Si on est pointilleux c'est une différence avec l'original :-)

    Pour le non-perliste que je suis, je pense être arrivé à comprendre à peu près ta version. Ton objectif de démontrer que le langage PERL peut être lisible me semble atteint !

    • [^] # Re: L'infini

      Posté par . Évalué à 3.

      Je vois que tu as géré le cas où les deux dates sont similaires en affichant "Tempo : ∞". Bonne idée, même si c'est peu probable d'arriver il faut que je le rajoute :-)

      Je vois peu de cas pendant lesquels ça peut arriver, mais par exemple comment se comporte la fonction pour récupérer l'heure si un changement d'heure à lieu pile au mauvais moment?
      Pour moi, ce qu'il a fait, c'est le genre de choses qui rendent un programme robuste.

      En plus, ça fait gagner des points au golf.

      • [^] # Re: L'infini

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

        Effectivement, il y a peu de chances pour que ça arrive mais ça coûte rien d'y penser : je ne sais pas sur quel simulateur ce script tournera.

        Si un changement soudain de temporalité survient (par exemple si l'utilisateur change la date sur le système sous-jacent), je ne vois pas bien ce que ça change : s'il va dans le futur brusquement, il obtiendra probablement rien car le script se ré-initialise après 5 secondes d'inactivité ; s'il va dans le passé subitement, il obtiendra un bpm négatif et ça correspondra bien à la réalité perçue du point de vue du script : il fait ce qu'on lui a demandé même si c'est le Docteur Who qui appuie sur la touche entrée.

        Le seul problème réel est dans le cas d'une durée nulle : une durée nulle ça n'existe pas, c'est seulement une absence de durée : ça n'aurait pas les propriétés qu'on peut légitimement attendre d'une durée.

        • [^] # Re: L'infini

          Posté par . Évalué à 5.

          s'il va dans le passé subitement, il obtiendra un bpm négatif et ça correspondra bien à la réalité perçue du point de vue du script : il fait ce qu'on lui a demandé

          Si tu peux bien sur inventer le besoin et la spécification que tu veux, je pense que la majorité des personnes saines d'esprit comprendrons l’énoncé du problème en CLOCK_MONOTIC et non en CLOCK_REALTIME. Ta vision me semble pour le moins farfelue.

          • [^] # Re: L'infini

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

            Je suis un être humain et je fonctionne en realtime depuis qu'on m'a booté : TapTempo Perl6 s'adresse à des êtres humains, il est écrit par un humain et il réponds à des humains capable de comprendre l'infini, pas de le calculer.

            • [^] # Re: L'infini

              Posté par . Évalué à 2.

              Difference between CLOCK_REALTIME and CLOCK_MONOTONIC? ;-)

              Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.

            • [^] # Re: L'infini

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

              Je suis un être humain et je fonctionne en realtime depuis qu'on m'a booté

              Je ne connais aucun humain qui fonctionne en realtime mais tous ceux que je connaisse fonctionne en monotonic. Une preuve, c'est que les changements d'heure ou de fuseau horaire posent problème.

              « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

      • [^] # Re: L'infini

        Posté par . Évalué à 5. Dernière modification le 01/03/18 à 17:58.

        Je vois peu de cas pendant lesquels ça peut arriver, mais par exemple comment se comporte la fonction pour récupérer l'heure si un changement d'heure à lieu pile au mauvais moment?
        Pour moi, ce qu'il a fait, c'est le genre de choses qui rendent un programme robuste.

        Si tu veux rendre un programme robuste, enfin surtout correct, tu utilises une horloge monotone pour mesurer un écart de temps. Ce que la version C++ faisait correctement et qui s'est perdu ici :)

        Le ∞ c'est juste utile si tu dépasses la résolution.

        • [^] # Re: L'infini

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

          Dans la version originale, si on considère la méthode TapTempo::computeBPM seule, rien ne garantit que les arguments currentTime et lastTime ne sont pas similaires. Dans les faits l'appelant ne pourra pas le faire, mais la vérification est la bienvenue pour éviter des erreurs dans le futur si le code évolue.

    • [^] # Re: L'infini

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

      Bonjour et merci à toi car ta démarche m'a inspiré, je trouve que ce que tu as fait avec Taptempo est très chouette.

      Les exits servent à éviter que mon script plante comme un gros tas au cas où l'utilisateur lui demanderait de faire des choses déraisonnables, comme par exemple demander un nombre négatif de chiffres après la virgule ou bien calculer une durée à partir d'un seul échantillon : dans un premier je type fortement les données que l'utilisateur essaye de transmettre au programme, ensuite je lis le cahier des charges et je réduis la voilure au maximum.

      De manière générale, je ne programme jamais mais quand je le fais, je fais tout pour que le programme refuse de fonctionner le plus souvent possible. C'est pour la même raison que je teste si du temps s'est écoulé entre deux dates avant de faire une division par la durée entre ces deux dates, ça évite de faire un division par zéro et ça donne la bonne réponse à la place.

  • # Perl 6, pas PERL 6

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

    Y a pas vraiment de séparation entre perl, Perl et PERL comme en Perl 5. (l'interpreteur, le langage et l'acronyme) :)

    Tu peux aussi te priver de l'utilisation du type Date. now est un Instant et des différences d'Instant te donne un type Duration. C'est suffisant pour obtenir ce que tu veux.

Suivre le flux des commentaires

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