기호 함수: catcode 및 \tl_rescan:nn 변경

기호 함수: catcode 및 \tl_rescan:nn 변경

목표는 사용자가 (인수를 위해) 하나의 변수에 선형 함수를 입력하도록 하는 것입니다(예: 2*x+3변수(중요하지 않음) 및 변수 값). 그런 다음 함수의 값을 계산하고 싶습니다. 다음은 효과가 있지만 지금은 다른 것보다 우연히 더 많이 작동한다고 생각하고 있습니다.

  1. 내 원래 시도는 \findvalueB실패했고 밑줄이 마음에 들지 않는 것 같아서 \findvalueA효과가 있는 방법을 시도했습니다. 왜 이 중 하나는 작동하고 다른 하나는 작동하지 않습니까?

  2. 테스트할 변수 이름을 전환하기로 결정했을 때 명백한 문제에 부딪혔습니다(예: ybreak 사용 \mytoks). 그래서 변수 이름을 하드코딩하려고 시도했지만 다시 실패했습니다. 기본 아이디어는 하단에 표시된 대로 작동하는 것 같습니다. 이 시도가 실패하는 이유는 무엇입니까?

아마도 제가 이해하지 못한 내용에는 공통된 내용이 있을 것 같고, 제가 바로잡고 싶은 것에 대한 근본적인 오해일 가능성이 높습니다. 둘 다 좋을지라도 코드 솔루션보다 설명에 더 관심이 있습니다.

\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}

답변1

방법 B의 실패는 설명하기가 매우 쉽습니다. 자료를 다시 스캔하면 현재 적용 가능한 카테고리 코드로 읽혀집니다. 때를사용 \findvalueB, 당신은 문서에 있고 '문자'가 아닌 '수학 첨자' 카테고리도 있습니다( 조금 나중에 _그것이 틀렸다는 것을 알게 될 것입니다 ). :사람들은 명령이 정의되었을 때 설정된 코드를 재검색에서 사용할 것이라고 상상하면서 종종 이에 놀랐습니다. 이것이 재스캔을 사용하는 것을 매우 까다롭게 만드는 것 중 하나입니다.

방법 C의 실패는 파악하기가 더 어렵습니다. 여기서 일어나는 일은 토큰화를 변경할 때(예를 들어 또는 에서 ) \defx다른 제어 시퀀스 뒤에 공백을 삽입하는 것과 마찬가지로 TeX가 재검색을 수행할 때 '유용하게' 공백을 삽입한다는 것 입니다. 이는 재검색 '이전'에 발생하며 단일 토큰이 됩니다. 결과적으로 메서드 C에서는 뒤에 필수 공백이 따라오는 것으로 정의됩니다. 공백이 없으므로 오류가 발생합니다. 방법 A에서는 공백이 전후에 삽입되므로 이러한 현상이 발생하지 않습니다 ( 재검색 전의 별도 토큰임). 따라서 이 방법이 효과가 있을 것입니다.\write\detokenize\defxx\def#1

이 두 가지 문제는 많은 TeX 프로그래머가 재검색을 선호하지 않는 이유를 보여줍니다. 저는 이를 피하는 경향이 있습니다. 우리는 LaTeX3에서 합리적인 래퍼를 제공했지만 귀하의 문제는 여전히 올바른 래퍼를 제공하기 어렵다는 것을 보여줍니다. 실제로 원하는 것은 모든 변수 문자를 값으로 바꾸는 것입니다. 그러므로 나는 전혀 다시 스캔하지 않을 것이지만

\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 }
  }

이러한 문제가 전혀 없습니다. (예를 들어 sin표현식과 문자 에 가능한 변수가 없다고 가정합니다 n. 이러한 경우는 처리할 수 있지만 더 많은 생각이 필요합니다!)

관련 정보