Funções simbólicas: alteração de catcodes e \tl_rescan:nn

Funções simbólicas: alteração de catcodes e \tl_rescan:nn

O objetivo é fazer com que o usuário insira (para fins de argumentação) uma função linear em uma variável, por exemplo, 2*x+3junto com a variável (isso não é crucial) e um valor para a variável. Gostaria então de calcular o valor da função. O seguinte funciona, mas agora estou pensando que funciona mais por acidente do que qualquer outra coisa.

  1. Minha tentativa original \findvalueBfalhou e não pareceu gostar do sublinhado, então tentei o método \findvalueAque funcionou. Por que um deles funciona e o outro não?

  2. Ao decidir mudar os nomes das variáveis ​​para teste, me deparei com problemas óbvios (por exemplo, usando ybreaks \mytoks. Então tentei codificar um nome de variável, novamente falha. A ideia básica parece funcionar como mostrado na parte inferior. Por que essa tentativa falha?

Presumivelmente, há um ponto comum no que não estou entendendo e é provavelmente um mal-entendido fundamental de algo que gostaria de corrigir. Estou mais interessado na explicação do que em uma solução de código, embora ambos sejam bons.

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\newtoks\mytoks

\NewDocumentCommand {\findvalueA} { m m m }
    {
        \group_begin:
        \char_set_catcode_active:N #1
        \tl_rescan:nn{}{\def#1{#2}}
        \tl_rescan:nn{}{\mytoks={#3}}
        \fp_set:Nn \l_tmpa_fp {\the\mytoks}
        \fp_use:N \l_tmpa_fp
        \group_end:
    }

\NewDocumentCommand {\findvalueB} { m m m }
    {
        \group_begin:
        \char_set_catcode_active:N #1
        \tl_rescan:nn{}{\def#1{#2}}
        % underscores=bad
        \tl_rescan:nn{}{\tl_set:Nn \l_tmpa_tl {#3}}
        % or
        % \tl_rescan:nn{}{\fp_eval:n {#3}}
        \fp_use:N \l_tmpa_fp
        \group_end:
    }

    \NewDocumentCommand {\findvalueC} { m m }
    {
        \group_begin:
        \char_set_catcode_active:N x
        \tl_rescan:nn {} {\defx{#1}}
        \tl_rescan:nn {} {\mytoks={#2}}
        \fp_set:Nn \l_tmpa_fp {\the\mytoks}
        \fp_use:N \l_tmpa_fp
        \group_end:
    }

\ExplSyntaxOff
\begin{document}

% works
\findvalueA{x}{5}{2*x+3}

% fails
%\findvalueB{x}{5}{2*x+3}

% fails
%\findvalueC{5}{x+2}

The method of findvalueC works down here but not above: if $x=5$, then $x+2=$
\ExplSyntaxOn
\group_begin:
\char_set_catcode_active:N x
\defx{5}
\fp_eval:n {x+2}
\group_end:
\ExplSyntaxOff

\end{document}

Responder1

O fracasso do método B é muito fácil de explicar. A nova digitalização do material o lê com os códigos de categoria atualmente aplicáveis. Quando vocêusar \findvalueB, você está no documento e também _tem a categoria 'subscrito matemático', não 'letra' (você também descobrirá que isso :está errado, um pouco mais tarde). As pessoas muitas vezes ficam surpresas com isso, pois imaginam que a nova varredura usará os códigos definidos quando o comando foi definido. Isso é algo que torna o uso da nova digitalização bastante complicado.

A falha do método C é mais difícil de detectar. O que acontece aqui é que o TeX insere 'de forma útil' um espaço depois \defxde fazer a nova varredura, da mesma forma que faz depois de qualquer outra sequência de controle ao alterar a tokenização (por exemplo, em \writeou \detokenize). Isso acontece 'antes' da nova varredura, onde \defxestará um único token. O resultado é que no método C xé definido como sendo seguido por um espaço obrigatório: não há espaço, então obtemos o erro. Isso não acontece no método A, pois o espaço aqui é inserido antes \defe depois #1(são tokens separados antes da nova varredura). Portanto, este método funcionará.

Ambas as questões mostram por que a nova varredura não é preferida por muitos programadores de TeX: eu tendo a evitá-la. Fornecemos wrappers razoáveis ​​no LaTeX3, mas seus problemas mostram que ainda é difícil acertar. O que você realmente deseja é substituir todas as letras das variáveis ​​pelo valor. Portanto, eu não verificaria novamente, mas usaria

\NewDocumentCommand { \findvalueD } { m m m }
  {
    \tl_set:Nn \l_tmpa_tl {#3}
    \tl_replace_all:Nnn \l_tmpa_tl {#1} {#2}
    \fp_eval:n { \l_tmpa_tl }
  }

que não tem nenhum desses problemas. (Presumo que você não tenha, por exemplo, sina expressão e a letra ncomo uma possível variável: tal caso poderia ser tratado, mas precisaria de mais reflexão!)

informação relacionada