인수(예: #1)에 대한 참조(인수 #1)가 새 값으로 확장되도록 인수(예: #1)의 값을 변경하는 방법은 무엇입니까?

인수(예: #1)에 대한 참조(인수 #1)가 새 값으로 확장되도록 인수(예: #1)의 값을 변경하는 방법은 무엇입니까?

변경 사항을 따르는 모든 값이 원래 값(외부에서 매크로로 전달됨)이 아닌 수정된 값을 포함하도록 #1해당 값을 기반으로 를 다른 것으로 변경하는 방법이 궁금합니다 .#1

\def\myT#1%
  {%
    \ifnum#1=0
      % #1=1
    \fi
    #1
  }
\myT{0} % 1
\myT{1} % 1
\myT[2} % 2

편집(해결 방법: 아래와 같이 의 인수로 중첩된 항목을 확장하는 것보다 #1처럼 의 값을 직접 변경하는 것이 좋습니다):#1=1\myT1

\def\myT#1%
  {%
    \ifnum#1=0
      \myT{1}%
    \else
      #1%
    \fi
  }
\myT{0} % 1
\myT{1} % 1
\myT{2} % 2

답변1

#1적절한 인수를 사용하는 것 외에는 값을 "할당"할 수 없습니다 .

제시하는 작업 유형은 두 개의 매크로를 사용하여 더 편리하게 수행됩니다. \myT{1}원래 인수가 인 경우 호출할 수 있지만 0이는 이미 수행된 검사를 다시 수행하므로 비효율적입니다.

\def\myT#1{%
  \ifnum#1=0
    \myTaux{1}%
  \else
    \myTaux{#1}%
  \fi
}
\def\myTaux#1{-#1-\par}

\myT{0} % 1
\myT{1} % 1
\myT{2} % 2

\bye

원하는 기능의 작동을 두 개 이상의 매크로로 분할하는 데에는 아무런 문제가 없습니다. 반대로 이는 일반적으로 좋은 습관입니다.

답변2

tex는 함수형 언어가 아닌 매크로 처리 언어라는 점을 기억하세요. #1함수에 대한 참조로 전달된 변수를 참조하는 식별자가 아니며, 제공된 토큰이 인라인되는 단순한 자리 표시자입니다.

따라서 무엇이든 할당하는 것이 의미가 있는지 여부는 #1무엇 #1인지에 따라 다릅니다.

주어진

\def\myT#1%
  {%
    \ifnum#1=0
       #1=1 %HERE
    \fi
    #1 %THERE
  }
\myT{0} % 1

HERE라고 표시된 줄은 0=1할당이 아니므로 단순히 0=1로 조판합니다. 그러나 동일한 정의를 사용했지만 다음과 같이 호출한 경우

\newcount\zzz
\zzz=0
\myT{\zzz}

그런 다음 HERE로 표시된 줄은 \zzz=1할당이 될 것이지만 THERE로 표시된 줄은 \zzz조판되지 않아 다음과 같이 평가될 것입니다 1.\the#1\the\zzz

답변3

"인수의 값 변경"이라고 설명하는 프로세스에 가장 가까운 프로세스는 문제의 인수가 변경된 상태에서 문제의 매크로가 다시 호출되도록 하는 것입니다.

어떤 조건에 따라 루틴이 마지막으로 수행하는 작업이 종료되고 자신을 다시 호출하는 이 프로그래밍 기술을 꼬리 재귀라고 합니다.

(La)TeX 용어: (La)TeX 매크로는 일부 조건에 따라 확장의 결과로 전달된 마지막 토큰이 다른 호출을 형성할 때 꼬리 재귀적입니다.

\if.. \else.. \fi꼬리 재귀 종료 조건을 확인하기 위해 -스위치가 필요한 경우 해당 매크로가 다시 호출되기 전에 일치하는 \else- 및 \fi-분기를 형성하는 토큰이 입력 버퍼에서 처리/폐기되는지 확인하십시오. 그렇지 않으면 문제의 매크로는 꼬리 재귀가 아닙니다. 이러한 분기를 형성하는 토큰은 재귀가 이미 종료된 시점에 처리될 때까지 토큰 스트림/입력 버퍼에 남아 축적되어 불필요한 작업을 수행하게 됩니다. 의미 체계에 큰 피해를 입히고 입력 버퍼에 불필요한 토큰 축적을 초래합니다.

예를 들어 다음과 같이 할 수 있습니다.

\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\def\myT#1{%
  \ifnum#1=0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
   {\myT{1}}{#1}%
}%
\myT{0}% 1

\myT{1}% 1

\myT{2}% 2
%...
\bye

보다 정교한 변경이 필요한 경우 필요한 확장 단계를 트리거한 후 인수를 교환하는 것이 좋을 수 있습니다. 두 개의 인수를 처리하는 매크로를 가정하고 첫 번째 인수의 값이 0인 경우 해당 인수는 값이 1인 인수로 대체되어야 하고 두 번째 인수는 값이 1만큼 증가하는 인수로 대체되어야 합니다.

% this example requires eTeX-extensions (\numexpr):
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\long\def\passfirsttosecond#1#2{#2{#1}}%
\def\myT#1#2{%
  \ifnum#1=0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
  {%
    \expandafter\passfirsttosecond\expandafter{\number\numexpr#2+1\relax}{\myT{1}}%
  }{%
    Value of 1st arg: #1.\hfil\break
    Value of 2nd arg: #2.%
  }%
}%
\myT{0}{5}% Value of 1st arg: 1.\hfil\break Value of 2nd arg: 6.

\myT{1}{6}% Value of 1st arg: 1.\hfil\break Value of 2nd arg: 6.

\myT{2}{7}% Value of 1st arg: 2.\hfil\break Value of 2nd arg: 7.
%...
\bye

세 개 이상의 인수를 변경해야 하는 경우 의 두 번째 인수 \passfirsttosecond내에 호출을 중첩할 수 있습니다. \passfirsttosecond이렇게 하면 변경해야 하는 마지막 k 번째 매크로 인수의 변경이 첫 번째 k 번째 \passfirsttosecond지시문을 수행하기 직전에 수행되는 패턴을 얻게 됩니다.

9개의 인수를 처리하는 매크로를 가정하고 값이 0인 첫 번째 인수의 경우 해당 인수는 값이 1인 인수로 대체되어야 하고 다음 인수는 각각 값이 다음만큼 증가하는 인수로 대체되어야 합니다. 1:

% this example requires eTeX-extensions (\numexpr):
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\long\def\passfirsttosecond#1#2{#2{#1}}%
\def\myT#1#2#3#4#5#6#7#8#9{%
  \ifnum#1=0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
  {%
    \expandafter\passfirsttosecond\expandafter{\number\numexpr#9+1\relax}{%
      \expandafter\passfirsttosecond\expandafter{\number\numexpr#8+1\relax}{%
        \expandafter\passfirsttosecond\expandafter{\number\numexpr#7+1\relax}{%
          \expandafter\passfirsttosecond\expandafter{\number\numexpr#6+1\relax}{%
            \expandafter\passfirsttosecond\expandafter{\number\numexpr#5+1\relax}{%
              \expandafter\passfirsttosecond\expandafter{\number\numexpr#4+1\relax}{%
                \expandafter\passfirsttosecond\expandafter{\number\numexpr#3+1\relax}{%
                  \expandafter\passfirsttosecond\expandafter{\number\numexpr#2+1\relax}{%
                    \expandafter\passfirsttosecond\expandafter{\number\numexpr#1+1\relax}{%
                      \myT
                    }%
                  }%
                }%
              }%
            }%
          }%
        }%
      }%
    }%
  }{%
    Value of 1st arg: #1.\hfil\break
    Value of 2nd arg: #2.\hfil\break
    Value of 3rd arg: #3.\hfil\break
    Value of 4th arg: #4.\hfil\break
    Value of 5th arg: #5.\hfil\break
    Value of 6th arg: #6.\hfil\break
    Value of 7th arg: #7.\hfil\break
    Value of 8th arg: #8.\hfil\break
    Value of 9th arg: #9.%
 }%
}%
\myT{0}{4}{9}{14}{19}{24}{29}{34}{39}%
%    Value of 1st arg: 1.\hfil\break
%    Value of 2nd arg: 5.\hfil\break
%    Value of 3rd arg: 10.\hfil\break
%    Value of 4th arg: 15.\hfil\break
%    Value of 5th arg: 20.\hfil\break
%    Value of 6th arg: 25.\hfil\break
%    Value of 7th arg: 30.\hfil\break
%    Value of 8th arg: 35.\hfil\break
%    Value of 9th arg: 40.%

\myT{1}{5}{10}{15}{20}{25}{30}{35}{40}%
%    Value of 1st arg: 1.\hfil\break
%    Value of 2nd arg: 5.\hfil\break
%    Value of 3rd arg: 10.\hfil\break
%    Value of 4th arg: 15.\hfil\break
%    Value of 5th arg: 20.\hfil\break
%    Value of 6th arg: 25.\hfil\break
%    Value of 7th arg: 30.\hfil\break
%    Value of 8th arg: 35.\hfil\break
%    Value of 9th arg: 40.%

\myT{2}{1}{2}{3}{4}{5}{6}{7}{8}%
%    Value of 1st arg: 2.\hfil\break
%    Value of 2nd arg: 1.\hfil\break
%    Value of 3rd arg: 2.\hfil\break
%    Value of 4th arg: 3.\hfil\break
%    Value of 5th arg: 4.\hfil\break
%    Value of 6th arg: 5.\hfil\break
%    Value of 7th arg: 6.\hfil\break
%    Value of 8th arg: 7.\hfil\break
%    Value of 9th arg: 8.%
%...
\bye

위의 예에서 볼 수 있듯이 (La)TeX 프로그래밍, 특히 (La)TeX의 "확장" 개념은 변수에 값을 할당하는 것에 관한 것이 아니라 토큰을 가져갈 수 있는 동안 소위 토큰을 소용돌이치는 것에 관한 것입니다. 토큰 스트림/입력 스트림에 차례로 배치되는 사물/항목입니다.

(La)TeX의 매크로 확장 개념을 접할 때 다음 비유가 도움이 될 수 있습니다.

(La)TeX가 .tex 입력 파일, 즉 (La)TeX 소스 코드의 일부를 처리할 때 첫 번째 단계에서는 토큰을 토큰 스트림. (이러한 토큰은 카테고리 코드, 제어 단어 토큰 및 제어 기호 토큰의 문자 토큰일 수 있습니다.) 이후 단계에서 이러한 토큰이 처리됩니다. 확장 단계에서 토큰은 제거/다른 토큰으로 대체됩니다. 확장 단계에서는 토큰 스트림에 토큰이 나타나는 순서도 변경될 수 있습니다.

.tex-input-file을 읽을 때 토큰 스트림에 토큰을 삽입하기 위해 (La)TeX가 따르는 규칙에 대한 세부 사항에 관심이 있는 경우 토론을 참조하세요."소스코드 들여쓰기"당신이 관심을 가질 수도 있습니다.

(La)TeX에 어떤 종류의 토큰이 있는지에 관심이 있는 경우 토론을 참조하세요."'매크로'와 '명령'의 차이점은 무엇입니까?"당신이 관심을 가질 수도 있습니다.

(La)TeX에서 매크로 인수가 처리되는 방법에 관심이 있는 경우 토론을 참조하세요."TeX는 구분된 인수를 어떻게 찾나요?"당신이 관심을 가질 수도 있습니다.

확장 속임수에 관심이 있는 경우 토론"csname 매크로에 추가할 때 확장 후 수를 어떻게 알 수 있나요?"당신이 관심을 가질 수도 있습니다.


Siracusa가 이미 지적했듯이 (La)TeX가 토큰 스트림에서 해당 인수를 수집한 경우 매크로 인수에 다른 토큰 시퀀스를 할당할 수 없습니다.
그러나 최종적으로 어떤 토큰이 전달될지 "결정"하기 위해 (La)TeX가 해당 인수를 검사하도록 할 수 있습니다. 이는 직접 수행하거나 전달된 인수가 검사 결과에 따라 달라지는 다른 매크로를 호출하여 수행할 수 있습니다.

직접 접근의 예:

\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\def\myT#1{%
  \ifnum#1=0 %<- The space before the percent terminates \ifnum's second number, i.e., the number 0. It gets discarded silently.
    \expandafter\firstoftwo%<-\expandafter removes the tokens that form the else-branch and the \fi
  \else
    \expandafter\secondoftwo%<-\expandafter removes the \fi
  \fi
  {1}{#1}%
}%
\myT{0} % 1
\myT{1} % 1
\myT[2} % 2

일반적으로 \romannumeral소문자로 된 정수의 로마 표기법을 형성하는 토큰을 얻는 데 사용됩니다. 숫자 검색 으로 인해 \romannumeral(La)TeX는 숫자를 찾거나 오류 메시지가 나타날 때까지 확장 가능한 토큰을 계속 확장합니다. 문제의 숫자가 양수가 아닌 경우 (La)TeX는 토큰을 전달하지 않고 조용히 이를 삼킵니다. 따라서 \romannumeral결국 (La)TeX가 양수가 아닌 숫자를 찾는 한 많은 확장 작업과 인수 검토 작업을 트리거하는 데 (ab?) 사용할 수 있습니다 .

직접 접근 방식의 또 다른 예는 확장을 위한 트리거로 호출하여 두 확장 단계 후에/찾은 장소를 두 번 "친 후" 어떤 경우에도 결과가 전달되도록 보장 \romannumeral하는 것입니다 .\myT\myT\expandafter

\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\def\myT#1{%
   \romannunmeral0%<-While searching the number for \romannumneral, (La)TeX finds the digit-token 0 and keeps
                  %   triggering expansion while searching in the token-stream for
                  %   more digit-tokens or something that terminates the number.
   \ifnum#1=0 %<- The space before the percent terminates \ifnum's second number, i.e., the number 0. It gets discarded silently.
     \expandafter\firstoftwo%<-\expandafter removes the tokens that form the else-branch and the \fi
   \else
     \expandafter\secondoftwo%<-\expandafter removes the \fi
   \fi
   { 1}{ #1}% <- The space that precedes `1`/`#1` will be right
            %    behind the "0" from "\romannumeral0".
            %    Therefore it stops (La)TeX's seeking for digits for
            %    \rommanumeral which means that after doing
            %    expansion-work/argument-examining-work (La)TeX
            %    does only find the non-positive number "0" and 
            %    thus the result/effect of `\romannumeral` is:
            %    "Triggering doing a lot of expansion- and argument-
            %     examining-work while silently discarding the
            %     digit-token 0 which forms a non-positive number
            %     and the space behind it and not delivering
            %     anything in roman-notation at all."
}%
\myT{0} % 1
\myT{1} % 1
\myT[2} % 2

다른 매크로를 호출하는 예:

\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\newcommand\myinnerT[1]{%
  Here \firstoftwo{\LaTeX}{} can do to the argument, #1, whatever shall be done.%
}%
\def\myT#1{%
  % Here the argument is examined for deciding how to call \myinnerT:
  \ifnum#1=0 %
    \expandafter\firstoftwo
  \else
    \expandafter\secondoftwo
  \fi
  {\myinnerT{1}}{\myinnerT{#1}}%
}%
\myT{0} % 1
\myT{1} % 1
\myT[2} % 2

위의 예에서는 확장의 일부 단계에서 인수가 숫자를 생성하는지 여부를 확인하는 것이 구현되지 않았습니다. (엄밀히 말하면 인수가 임의의 토큰 시퀀스로 구성될 수 있는 경우 이러한 검사는 불가능합니다. 이 경우 인수를 형성하는 토큰 자체가 어떤 알고리즘의 (La)TeX 구현을 형성할 수 있으므로 이러한 검사는 (아래에서) 다른 것) 해결이 필요합니다.정지 문제.)

관련 정보