3

Inspired by a question yesterday, I thought I'd try my hand at a LaTeX3 solution which would show how to convert base 10 numbers into any other base of the user's choice.

Yesterday I wrote a nice simple version that worked. But today, I decided I wanted to separate the building of the steps from the process of outputting and formatting those steps. I also thought it would be interesting to explore the possibilities of creating the effect of an array within an array using sequences and token lists.

But now, I'm getting an error.

\documentclass{article}
\usepackage{amsmath,amssymb}
\usepackage{xparse}
\pagestyle{empty}
\ExplSyntaxOn
%% setting and getting the base
\int_new:N \g__new_base_int
\NewDocumentCommand{\setbase}{ m }{
    \int_gset:Nn \g__new_base_int { #1 }
}
\NewDocumentCommand{\getbase}{}{
    \int_use:N \g__new_base_int
}
%% setting and getting the number to be converted
\int_new:N \g__number_to_convert_int
\NewDocumentCommand{\setnumber}{ m }{
    \int_gset:Nn \g__number_to_convert_int {#1}
}
\NewDocumentCommand{\getnumber}{ }{
    \int_use:N \g__number_to_convert_int
}

%%---internal function to build each step in the conversion process
%%---and the parameters to be used for this function
\int_new:N \l__quotient_int
\int_new:N \l__tmp_new_quotient_int
\int_new:N \l__remainder_int
\seq_new:N \g__steps_of_conversion
\cs_new:Nn \__build_steps_of_conversion: {
    \int_set_eq:NN \l__quotient_int  \g__number_to_convert_int
    \int_do_while:nn { \l__quotient_int >= \g__new_base_int }
        {
            \int_set:Nn \l__remainder_int {  \int_mod:nn { \l__quotient_int } { \g__new_base_int } }
            \int_set:Nn \l__tmp_new_quotient_int { \int_div_truncate:nn { \l__quotient_int } {\g__new_base_int }}
            \exp_args:NNx \seq_gput_right:Nn \g__steps_of_conversion 
                {  
                    {\int_use:N \g__new_base_int  }
                    {\int_use:N \l__quotient_int  }
                    {\int_use:N \l__remainder_int }
                    {\int_use:N \l__tmp_new_quotient_int}
                }
            \int_set_eq:NN \l__quotient_int \l__tmp_new_quotient_int
        }
}
%%---internal function to construct the display of the conversion process
\bool_new:N \l__first_item_on_line_bool
\cs_new:Nn \__show_steps_of_conversion: {
    \__build_steps_of_conversion:
    \seq_map_inline:Nn \g__steps_of_conversion 
        {
            \bool_set_true:N \l__first_item_on_line_bool
            \tl_map_inline:nn { ##1 } {
                \bool_if:NF \l__first_item_on_line_bool { & }
                ###1 
                \bool_set_false:N \l__first_item_on_line_bool
            }
            \\
        }
}
%%---user interface to displaying the conversion
\NewDocumentCommand{\showstepsofconversion}{ o }{
    \[
        \begin{array}{crc|r}
            \text{Base} & & \text{R} & \text{Q} \\\hline
            \__show_steps_of_conversion: 
        \end{array}
    \]
}
%% accessing and using LaTeX3's internal base conversion
\NewDocumentCommand{\converttobase}{m}{
    \int_to_base:nn {#1} \g__new_base_int
}
%%
\ExplSyntaxOff
\setlength{\parindent}{0pt}
\setbase{21}
\setnumber{2680010}
\begin{document}

The base is \getbase.  \getnumber{} becomes $\converttobase{\getnumber}_{\getbase}$.

\showstepsofconversion

\end{document}

The problem seems to be ###1. Oddly, the output is as I desire. The suggested correction to ##1 is clearly not correct and when I rewrite my code to ##1 I get the wrong value.

David Carlisle
  • 757,742
A.Ellett
  • 50,533
  • # must be doubled, so I guess you need ####1. – egreg Feb 02 '13 at 16:30
  • @egreg. That works. Thanks. But it also seem peculiar and counter-intuitive to how LaTeX usually works. Why the need for the doubling? – A.Ellett Feb 02 '13 at 16:32
  • Not related to the issue at hand, but expl3 code should always be set up in a defined namespace. So here you might have \showbaseconv_... as the function prefix, and therefore \l_showbaseconv_... for a local variable, etc. – Joseph Wright Feb 02 '13 at 16:33
  • @A.Ellett No, it's entirely how TeX works: each time you nest a level of definitions, you have to double up each #. – Joseph Wright Feb 02 '13 at 16:33
  • @JosephWright. True, true. Thanks for reminding me about the convensions. I keep slipping on them. – A.Ellett Feb 02 '13 at 16:34
  • When a replacement text for a macro contains #1 TeX substitutes the first argument; when it contains ## it substitutes #. (This is not the complete truth, but a good approximation.) – egreg Feb 02 '13 at 16:34
  • Then I guess I've misunderstood the TeX approach (probably because I usually never really nested things too much). Good to learn. – A.Ellett Feb 02 '13 at 16:35
  • Should I change the title to reflect this? Something like ###1 not parsing correctly – A.Ellett Feb 02 '13 at 16:38
  • there are several questions on doubling # already eg http://tex.stackexchange.com/questions/71632/why-do-paramaters-of-renewcommand-need-to-double-up-the-within-a-foreach/ – David Carlisle Feb 02 '13 at 16:42
  • @DavidCarlisle Perhaps we need a canonical question on this ([tag:tex-core]?) to link to – Joseph Wright Feb 02 '13 at 16:44
  • @josephwright. This whole matter of namespaces seems to result in unyieldy, long names. It seems like LaTeX3 could do with a healthy dose of encapsulation capabilities. Can you direct me to sources that will explain the choice for the current format? – A.Ellett Feb 02 '13 at 16:45
  • @A.Ellett Well the 'rules' are laid out in the expl3 concepts guide. The bottom line is TeX does not have a namespace system (and even if it did you'd still need to manage the module names). The formalised approach in expl3 is pretty much the same as good practice for LaTeX2e packages, where many packages use \foo@... in names. If you want more on this, probably best to ask on in chat or on LaTeX-L as it's likely to be a discussion. – Joseph Wright Feb 02 '13 at 16:49
  • 1
    I misconstrued my problem to be a LaTeX3 problem. It seems now from the feedback you all have given me that this is really a duplicate of the answer to the question Why do paramaters of \renewcommand need to double up the # within a \foreach – A.Ellett Feb 02 '13 at 16:50

1 Answers1

4

you want 4 # to refer to #1 in a macro definition. (This is primitive TeX parsing, not a LaTeX3 feature)

            ####1 

not

            ###1 
David Carlisle
  • 757,742