From 75d8dfa80524727ddb7d8ae217ed6463efba84cf Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Sun, 22 Mar 2020 03:00:48 +0000 Subject: CTAN sync 202003220300 --- .../expose-expl3-dunkerque-2019/dk19ecrireprem.tex | 400 +++++++++++++++++++++ 1 file changed, 400 insertions(+) create mode 100644 info/expose-expl3-dunkerque-2019/dk19ecrireprem.tex (limited to 'info/expose-expl3-dunkerque-2019/dk19ecrireprem.tex') diff --git a/info/expose-expl3-dunkerque-2019/dk19ecrireprem.tex b/info/expose-expl3-dunkerque-2019/dk19ecrireprem.tex new file mode 100644 index 0000000000..cff913ae23 --- /dev/null +++ b/info/expose-expl3-dunkerque-2019/dk19ecrireprem.tex @@ -0,0 +1,400 @@ +% Time-stamp: <2019-09-24 10:47:32 administrateur> +% Création : 2019-08-24T14:29:55+0200 +\section{Rappel} +\label{sec:rappel} + +Je commence par redonner le code de Donald E. \textsc{Knuth} mais je +laisse le lecteur rechercher l'article précité de Denis \textsc{Roegel} +pour y trouver toutes les explications nécessaires. + +\VerbatimInput[frame=lines, framesep=0.75\baselineskip, +label={\textsc{Knuth} \textemdash{} \emph{définitions}}, +labelposition=topline]{./codes/knuth-def.tex} + +L'appel |\primes{15}| permet d'obtenir +\og \primes{15}\fg. + +\section{Version avec \Expliii} +\label{sec:versionexpl3} + + +Commençons par quelques remarques: comme le code est écrit dans un +fichier \texttt{.tex} \TO et non dans un \gls{module} \TF je dois +commencer par enclencher la syntaxe propre à \Expliii{}, ce que je +fais dès la première ligne qui n'est pas un commentaire à usage +interne \TO d'où le décalage de numéro \TF dans le premier fragment +ci-dessous: +% +\Fragment{3}{5}{./codes/henel-def} + +\subsection{Une macro privée pour écrire les nombres} +\label{sec:macro+ecrire+entier} + +Sur la ligne~\(5\), on lit la définition d'une macro \emph{interne} +\CAD d'une macro qui n'a pas vocation à être appelée directement dans +un document rédigé par l'utilisateur final. On y voit déjà quelques +différences avec du code \LaTeXe{} que je vais préciser maintenant: +\begin{itemize} +\item les caractères |_| et~|:| sont promus au rang de lettres mais + par l'arobase~|@| cher aux programmeurs en~\LaTeXe{}; + +\item les espaces du code ne donneront pas d'espace dans le + document. Voilà qui soulage grandement le programmeur puisque + disparait la phase de recherche des \TdSTrad{blancs + inopportuns}{spurious blanks}. +\end{itemize} + +Autre remarque, d'ordre typographique, la présentation que j'adopte +dans ce document \TO pour des raisons de place\TF n'est pas la +présentation recommandée par l'équipe du projet \LaTeX3. On devrait +plutôt, en effet, adopter la présentation qui suit\index{présentation + du code}: +% +\begin{Verbatim}[frame=lines, framesep=0.75\baselineskip] +\cs_new:Nn \__yh_ecrire_nombre:n + { + \(\np{\int_to_arabic:n{ #1 }}\) + } +\end{Verbatim} +% +dont on m'accordera, j'espère, qu'elle occupe plus d'espace. + +La commande que je définis s'appelle +\Macro{__yh_ecrire_nombre:n}. Ce nom comporte plusieurs parties: +\begin{enumerate} + +\item les \og |__|\fg initiaux signalent que cette commande est + \emph{privée} \CAD que son usage est réservée au \gls{module} \TO + ici le simple fichier contenant le code\TF et n'est pas + nécessairement documentée. Le programmeur ne s'engage à rien sur + cette commande et un utilisateur du \gls{module} ne doit pas + s'attendre à ce que le comportement de cette commande reste stable + au fil des versions ni même à ce qu'elle soit toujours + disponible. Il ne s'agit ici que d'une \textsb{convention} car + \TeX{} est resté ce qu'il est et la gestion des espaces de noms + n'est pas implémentée\footnote{L'équipe des développeurs de + \Expliii{} nous dit, dans \autocite[p.~1]{expl3progr} que celà + pourrait se faire mais avec un surcoût prohibitif.}; + +\item \og |yh|\fg remplace ici ce qui est \TO dans un \gls{module}\TF + le nom du \gls{module} ou, à tout le moins, une chaine de caractères + réservée pour ce \gls{module}; + +\item vient le nom explicite de la commande: \og |ecrire_nombre|\fg + dans lequel le souligné~\og |_|\fg sert de séparateur de mots; + +\item suivi du caractère~\og |:|\fg qui introduit la \gls{signature} + de la commande qui est, ici, \og |n|\fg. Cela nous indique que la + commande est une \gls{fonction} \TO c'est le vocabulaire défini par le + projet \LaTeX3\TF qui attend un seul argument fourni entre + accolades. +\end{enumerate} + +La fonction \Macro{cs_new:Nn} utilise la \gls{signature} de la +commande qui suit pour déterminer le nombre et le type des arguments +que demande cette commande. Elle vérifie que la commande n'est pas +déjà définie et produit une erreur si c'est le cas. De plus, elle +définit la commande de manière globale \TO penser à \Macro{gdef} avec +les pouvoirs de \Macro{newcommand}\TF. + +Elle possède plusieurs variantes dont, \PX{}, \Macro{cs_new:cn} qui +attend comme premier argument le \emph{nom} de la commande plutôt que +la commande elle-même. J'aurais obtenu le même résultat avec: +% +\begin{Verbatim}[frame=lines, framesep=0.75\baselineskip] +\cs_new:cn { __yh_ecrire_nombre:n } { \(\np{\int_to_arabic:n{ #1 }}\) } +\end{Verbatim} +% +code que je livre compacté. + +Le 2\ieme argument de \Macro{cs_new:Nn} doit être fourni entre +accolades, c'est la définition de la commande. Ici j'utilise +\Macro{np} de l'extension \Pkg{numprint} en mode mathématique en +ligne \TO à l'aide du bien connu couple |\(| et~|\)| \TF afin +d'obtenir \og \(\np{3257}\)\fg au lieu de \og \(3257\)\fg. + +La \gls{fonction} \Macro{int_to_arabic:n} appartient au \gls{module} +\Mdl{int}, partie du noyau de \LaTeX3, qui regroupe les commandes +traitant les \glspl{entier}. Elle prend un argument dont elle fournit +la représentation en chiffres \emph{arabes}. + +\subsection{Commande vérifiant qu'un entier impair est premier} +\label{sec:macro+impair+premier} + +La commande \Macro{yh_impair_est_premier:nT} ne se déclare pas comme +privée, dans un \gls{module} elle devrait avoir une interface et une +sortie stable et être documentée car son nom ne commence pas par~|__| +mais ça aurait pu être le cas. + +\(2\) étant le seul nombre pair premier, la question de la primarité +ne se pose vraiment que pour les entiers impairs. Je pourrai donc +n'essayer que des diviseurs impairs. + +La \gls{signature} de cette \gls{fonction}, \CAD |nT|, nous indique +qu'elle attend deux arguments entre accolades, que le 1\ier sera un +test qui renverra soit~\VRAI{} soit~\FAUX{} et que, \emph{dans le seul + cas} où le test est~\VRAI{}, le code contenu dans la 2\ieme paire +d'accolades sera considéré. + +Regardons le code: +% +\Fragment{7}{25}{./codes/henel-def} + +Dans la partie d'initialisation \TO lignes~\(8\) à~\(10\)\TF, je crée +deux \glspl{booleen} \TO \Macro{yh_continue_bool} et +\Macro{yh_est_premier_bool}\TF à l'aide de la \gls{fonction} +\Macro{bool_set_true:N} qui, dans le même temps, leur donne la +valeur~\VRAI. + +Les \glspl{fonction} dont le nom contient |set| définissent les +commandes sans vérification et, à moins que le nom contienne |gset| +\TO |g| comme \og global\fg\TF, elles créent ces commandes +\emph{localement} \CAD{} dans le groupe où a lieu la définition. + +Ici, contrairement à ma devise\footnote{À savoir: \og ceinture et + bretelles\fg.}, je coure le risque que ces deux \glspl{booleen} +existent déjà, risque dont je pense qu'il est faible. On verra plus +bas ce que j'aurais pu faire pour sécuriser la définition. + +Ces deux \glspl{booleen} ne sont pas des \glspl{fonction} mais des +\glspl{variable} \CAD{} des macros \TO au sens de \TeX{}\TF dont le +seul objet est de contenir une valeur et non pas de \emph{faire} +quelque chose. C'est pour cela que leurs noms n'ont pas de +\gls{signature} et ne se termine pas par~|:| qui signalerait une +\gls{fonction} sans argument. + +Dernière étape de l'initialisation, avec \Macro{int_set:Nn} je donne +à la variable entière \textbf{l}ocale temporaire \Macro{l_tmpa_int} +la valeur~\(1\). Plusieurs \glspl{module} du noyau de \LaTeX3 +fournissent deux variables locales dont les noms comportent |tmpa| +et~|tmpb| respectivement et deux variables \textbf{g}lobales \TO avec +les noms équivalents\TF. + +Suivant la convention générale qui veut que le nom d'une +\gls{variable} se termine par son type \TO c'est le cas des deux +\glspl{booleen} que j'ai définis\TF, les variables temporaires +fournies par un \gls{module} du noyau ont une finale qui donne le type +comme \Macro{l_tmpa_int}. Cependant, contrairement à cette même +convention de nommage, les variables temporaires n'ont pas, en tête de +nom, le nom du module. On aura voulu éviter quelque chose comme +\Macro*{int_l_tmpa_int} dont on peut penser que c'est légèrement +redondant. + +En ligne~\(12\), je commence une boucle \TANTQUE avec +\Macro{bool_do_while:Nn} qui attend un premier argument constitué d'un +seul lexème \TO ici \Macro{yh_continue_bool} qui est~\VRAI à l'entrée +dans la boucle\TF et un deuxième argument entre accolades: le corps de +la boucle. + +Le corps de cette boucle commence avec l'accolade ouvrante du bout de +la ligne~\(12\) et s'achève avec la 2\ieme accolade fermante de la +ligne~\(24\). + +Je commence par ajouter~\(2\) à la valeur courante de +\Macro{l_tmpa_int} à l'aide de la \gls{fonction} \Macro{int_add:Nn}; +\Macro{l_tmpa_int} est ici le candidat diviseur. + +\Macro{bool_if:nTF} est une forme de~\SIALORSSINON: on a bien les deux +branches de l'alternative puisque la signature se termine en~|TF|. Il +s'agit de savoir si le candidat est bien un diviseur de l'entier +représenté par~|#2|. Pour ce faire, j'utilise la \gls{fonction} +\Macro{int_compare_p:nNn} dont le 2\ieme argument est un opérateur de +comparaison \CAD |>|, |<| ou~|=|. Le 3\ieme argument est +simplement~\(0\). Le premier, lui, est le reste de la division de~|#2| +par \Macro{l_tmpa_int} que l'on obtient à l'aide de la \gls{fonction} +\Macro{int_mod:nn}. + +Si le reste est nul, on exécute le code du 2\ieme argument de +\Macro{bool_if:nTF}. On positionne les deux \glspl{booleen} à~\FAUX{} +puisque |#2|, divisible par \Macro{l_tmpa_int}, n'est pas premier et +qu'il n'est donc pas nécessaire de reprendre la boucle. + +Si le reste n'est pas nul, je compare l'entier~|#2| et le carré du +candidat \TO on peut utiliser les opérateurs \emph{classiques} +d'opérations: |+|, |-|, |*|, |/| car, derrière ce code, c'est le +mécanisme de la macro \Macro{numexpr} de \hologo{eTeX} qui est à +l'œuvre\TF. Si le carré est plus grand, c'est que |#2|~est premier et +qu'il est temps de s'arrêter d'où les valeurs données aux deux +\glspl{booleen}. Le 3\ieme argument du \Macro{bool_if:nTF} s'arrête +avec la 1\iere accolade fermante de la ligne~\(24\). + +À la sortie de la boucle, si |#2| n'est pas premier il n'y a rien à +faire, s'il est premier, on le retourne. Cela est accompli à l'aide +de la \gls{fonction} \Macro{bool_if:nT} qui réalise un saut +conditionnel \SIALORS. + +\subsubsection{Compléments} +\label{sec:complementbouclesaut} + +Outre les deux \glspl{fonction} \Macro{bool_if:nTF} et +\Macro{bool_if:nT}, \Expliii fournit également la \gls{fonction} +\Macro{bool_if:nF} qui réalise un saut conditionnel \SISINON. Dans le +manuel, on verra que la signature se termine +par~\underline{\texttt{\emph{TF}}} pour signaler la présence des trois +signatures~|T|, |F| et~|TF|. + +Par ailleurs, \Expliii fournit essentiellement quatre boucles: +\begin{itemize} +\item \Macro{bool_do_while:Nn}, déjà rencontrée. C'est un \TANTQUE + dont le corps est exécuté puis le test effectué \CAD qu'en toutes + circonstances, le corps est exécuté au moins une fois; + +\item \Macro{bool_do_until:Nn}, qui inverse le sens du test. C'est un + \JUSQUA dont le corps est exécuté au moins une fois;\label{booldountilNn} + +\item \Macro{bool_while_do:Nn}, \TANTQUE qui commence par le + test. Il se peut donc que le corps ne soit pas exécuté; + +\item \Macro{bool_until_do:Nn}, \JUSQUA commençant par le + test. +\end{itemize} + +Ces quatres \glspl{fonction} ont des variantes de signatures~|cn| +et~|nn|. Avec~|cn|, le 1\ier argument est le nom d'un \gls{booleen}; +avec~|n|, c'est une expression booléenne comme \TO exemple tiré de +\autocite{l3interfaces}\TF +% +\begin{Verbatim}[frame=lines, framesep=0.75\baselineskip] +\int_compare_p:n { 1 = 1 } && + ( + \int_compare_p:n { 2 = 3 } || + \int_compare_p:n { 4 <= 4 } || + \str_if_eq_p:nn { abc } { def } + ) && +! \int_compare_p:n { 2 = 4 } +\end{Verbatim} +% +qui permet de mesurer la complexité acceptée. + +\subsection{Écrire la liste des nombres premiers} +\label{sec:ecrirelistepremiers} + +Avant d'aborder la commande destinée à l'utilisateur \TO dont je dirai +que c'est une \emph{commande de document}, comme le suggère le nom de +la macro qui permettra de la créer tout à l'heure. L'extension +\Pkg{xparse}~\autocite{xparse} parle de \English{document-level + command}\TF, je présente deux nouvelles macros utilitaires \TO +qui elles aussi auraient pu être \emph{privées}\TF à savoir +\Macro{yh_ecrire_separateur:n} et \Macro{yh_ecrire_si_premier:n}. + +\subsubsection{Deux macros utilitaires} + +\Fragment{27}{32}{./codes/henel-def} + +On voit dans le code ci-dessus, en ligne~\(27\), une pré-déclaration +de \Macro{yh_ecrire_separateur:n} qui permet juste de s'assurer que ce +nom est bien disponible. + +La macro suivante \Macro{yh_ecrire_si_premier:n} fait exactement ce +que son nom suggère. + +Passons maintenant à la commande principale. + +\subsubsection{La commande de document} +\label{sec:commandededocument} + +\Fragment{34}{59}{./codes/henel-def} + +Le code permettant de définir cette commande utilise l'extension +\Pkg{xparse}~\autocite{xparse} et sa macro \Macro{NewDocumentCommand}. + +La syntaxe de déclaration d'argument change quelque peu! Le |m|, +2\ieme argument de la macro, indique que l'on définit une commande +requérant un unique argument obligatoire fourni entre accolades \TO +|m| pour \English{mandatory} \CAD \og obligatoire\fg\TF. +% Le 1\ier argument est attendu \textsb{entre accolades} \TO pas de +% fantaisie à la \LaTeXe{}, du genre |\new|\0|com|\0|mand| +% |\truc|\dots{}, ici\TF. FAUX! +Le 1\ier argument est, comme on s'y attend, le nom de la commande +créée. + +Le corps de la définition commence en ligne~\(35\) en ouvrant un +groupe avec \Macro{group_begin:} et finit en ligne~\(59\) en fermant +le groupe avec \Macro{group_end:}. + +\paragraph{Initialisation} + +Dans le groupe, je crée en lignes~\(37\) et~\(38\) deux \glspl{entier} +locaux \TO d'où le |l| initial\TF mais qui seront créés +\emph{globalement}, car il n'y a pas moyen de faire autrement. Leur +caractère local est donc conventionnel mais signale que l'on ne doit +pas s'attendre à ce qu'ils aient une valeur pertinente à l'extérieur +du groupe. + +Pour respecter ce caractère local, je donne à ces \glspl{entier}, une +valeur avec \Macro{int_set:Nn} et pas avec \Macro{int_gset:Nn} qui, de +fait, n'est qu'un alias de la première, à moins que ce soit +l'inverse\footnote{Je ne suis pas allé vérifier dans le + source~\autocite{source3}.}. + +Afin que, en sortie de commande, ces deux \glspl{entier} ne soient +plus accessibles \TO \textsl{Vous êtes priés de laisser ces lieux dans l'état +où vous auriez aimé les trouver en entrant!} \TF, je les annihile en +lignes~\(57\) et~\(58\) à l'aide de \Macro{cs_undefine:N}. + +Il est temps à présent de définir, localement, avec \Macro{cs_set:Nn}, +la fonction \Macro{yh_ecrire_separateur:n}, ce que je fais en +ligne~\(41\) et~\(42\). Comme la définition est faite dans une +définition, on doit, bien entendu, recourir au doublement des +\emph{dièses} d'où le |##1| dans le code de cette fonction. + +Dans les 1\ier et 3\ieme arguments de \Macro{int_compare:nNnTF} on +peut écrire \emph{naturellement} des opérations sur les entiers. Je ne +m'en prive pas. + +Les tildes~|~| que l'on voit apparaitre en ligne~\(42\) permettent de +coder un espace qui apparaitra dans le document final. Par contre, il +faut utiliser autre chose pour coder un espace insécable \TO la +solution est la macro \Macro{nobreakspace}\TF. + +Je suis obligé de regarder si le séparateur est le dernier car, en +français\footnote{Encore que, si j'ai bien compris un article récent + paru dans la presse britanique, même à Oxford on a fini par + renoncer à la virgule devant le \emph{and} précédant le dernier mot + d'une énumération. \textsl{Tout fout l'camp, ma bonne dame!}} il ne +doit pas y avoir de virgule devant le \emph{et}. + +Comme l'annonce la ligne~\(43\) je ne calcule pas les deux premiers +nombres premiers \TO Donald \textsc{Knuth} ne le faisait pas\TF et je +ne vérifie pas que l'utilisateur demande au moins trois nombres \TO +même remarque\TF; pour faire comme dans les livres sérieux, je laisse +cette amélioration comme exercice pour le lecteur. + +Je prépare maintenant la boucle en initialisant, localement, le +\emph{candidat premier} à~\(3\). On a déjà vu \Macro{int_set:Nn}. +Et je rentre dans la boucle en ligne~\(50\) pour en sortir en +ligne~\(55\). La seule nouveauté de ce fragment de code est l'emploi +de \Macro{int_incr:N} qui permet d'incrémenter localement le compteur +\Macro{l_compteur_int}. + +J'ai déjà expliqué ci-dessus l'utilité des lignes~\(57\) à~\(59\). + +\subsection{Utilisation de la commande de document} +\label{sec:utilisation} + +Il me reste à utiliser cette commande dans ce document: +|\ListePremiers{15}| produit \og \ListePremiers{15}\fg. + +Au passage, on notera avec satisfaction que |\primes| et +|\ListePremiers| sont d'accord quant aux quinze premiers nombres +premiers. C'est rassurant. + +\subsection{Quelques commentaires subjectifs} +\label{sec:commentairessubjectifs} + +J'accorde sans peine qu'avec \Expliii le code est plus verbeux qu'avec +\TeX{} tout seul. Je ne peux, cependant, m'empêcher de penser qu'il +est plus clair. Pour ma part, le gain énorme que je vois en passant +cette fois de \LaTeXe{} à \Expliii{} c'est le systématisme du nommage +des macros, \glspl{fonction} ou \glspl{variable}. L'équipe du projet +\LaTeX3 en fait d'ailleurs, elle-même, un ``\emph{argument de + vente}''. + +La puissance de \Macro{NewDocumentCommand} \TO que l'on a à peine +effleuré ci-dessus\TF, à elle seule, peut inciter à passer à +\Expliii{} pour créer ses propres macros. + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "dun19expl3" +%%% End: -- cgit v1.2.3