왜 \expandafter\@firstoftwo 관용구를 사용하나요?

왜 \expandafter\@firstoftwo 관용구를 사용하나요?

{true}{false}조건부 테스트에 이어 다음 중 하나의 결과가 나오도록 정의된 쌍이 따르는 매크로가 많이 있습니다 .

\expandafter\@firstoftwo

또는

\expandafter\@secondoftwo

이것들이 왜 \expandafter거기 있는 걸까요? 나는 그들이 다음 쌍의 첫 번째 버팀대를 잡았을 것이라고 생각합니까 {true}{false}?

답변1

s \expandafter는 다음을 처리 \else하거나 \fi. Ryan이 링크한 질문에서와 같이 전체 코드는 다음과 같습니다.

\def\ifeq#1#2{%
 \ifx#1#2\relax
   \expandafter\@firstoftwo
 \else
   \expandafter\@secondoftwo
 \fi
}

무슨 일이 일어나는지 추적해 봅시다. 우리는 \ifeq\stuff\nonsense{true}{false}문서에 넣었습니다. 는 \ifeq흡수 \stuff하고 \nonsense첫 번째 확장 이후에는 다음과 같습니다.

\ifx\stuff\nonsense\relax
  \expandafter\@firstofone
\else
  \expandafter\@secondoftwo
\fi
{true}{false}

\stuff그것이 \nonsense(즉, 조건문이 참이라고) 가정해 봅시다 . 그런 다음 \ifx"진정한" 경로의 모든 항목을 확장하기 시작합니다. 이는 다음 항목까지의 모든 항목 \else또는 \fi(모듈로 중첩)로 정의됩니다. 중요한 점은 그것이 확장되기 시작한다는 것입니다.첫 번째\else또는 을 찾기 위해 미리 보지 않습니다 \fi. TeX는 그것이 도착하면 알게 될 것이라고 생각합니다. 그래서 우리는:

  \expandafter\@firstoftwo
\else
  \expandafter\@secondoftwo
\fi
{true}{false}

TeX는 이제 이를 확장합니다 \expandafter. 이는 \@firstoftwo에 도달하고 그것을 확장하는 효과가 있습니다 \else. "확장"은 스트림에서 \else일치하는 항목까지 모든 것을 제거하는 것을 의미합니다 . \fi이제 남은 것은 다음과 같습니다.

\@firstoftwo{true}{false}

그리고 이것은 간단한 true.

s 가 없으면 \expandafter다음을 수행할 수 있습니다.

  \@firstoftwo
\else
  \@secondoftwo
\fi
{true}{false}

TeX는 여전히 실제 분기를 확장하고 있으므로 확장됩니다 \@firstoftwo. 이는 스트림에서 두 개의 토큰/중괄호 그룹을 흡수합니다. 이것들은 \else과 입니다 \@secondoftwo. 그런 다음 스트림의 첫 번째 항목을 남기므로 우리는 다음을 얻습니다.

\else
\fi
{true}{false}

조건과 일치 하므로 TeX는 이것과 스트림에서 나가는 것 \else까지의 모든 것을 흡수합니다 . 그건 우리가 원했던 것이 아니었습니다.\fi{true}{false}

요약하자면, \expandafters조건부 처리를 방해하지 않도록 하는 것입니다.결과조건의 결과가 스트림의 다음 비트를 확인하고 완료되지 않은 조건의 비트가 남아 있지 않도록 보장합니다.

답변2

나는 이것을 다른 관점에서 공격하고 싶다. TeX의 기본 조건문은 조건의 참 또는 거짓이 확립될 때까지 입력 스트림에서 토큰을 흡수할 수 있는지 여부를 테스트하는 조건입니다. 따라서 <IF>흡수되어야 하는 토큰 목록(아마도 비어 있을 수 있음)과 함께 기본 조건을 표시해 보겠습니다 . 예를 들어 \ifhmode토큰이 필요하지 않고 \ifx두 개가 필요합니다. 어떤 경우에는 ( \if, \ifcat, \ifnum, \ifdim) TeX가 테스트에 필요한 토큰 종류를 찾기 위해 확장을 수행합니다. 다른 것( \ifx, \ifmmode, \ifhmode, \ifvmode \ifinner, \iftrue, \iffalse)에서는 확장이 수행되지 않습니다. 따라서 <IF>조건부 토큰과 필수 토큰이 표시됩니다.~ 후에확장이 이루어졌으며 상태를 테스트할 수 있습니다.

당신이 말하는 전형적인 건축은

<IF>
  \expandafter\@firstoftwo
\else
  \expandafter\@secondoftwo
\fi

우리가 이미 가지고 있는 곳

\long\def\@firstoftwo#1#2{#1}
\long\def\@secondoftwo#1#2{#2}

더 일반적으로, 우리는

<IF><true>\else<false>\fi

또는

\IF<true>\fi

여기서 <true>및 둘 다 <false>비어 있을 수 있습니다.

조건이 참이다

TeX는 단순히 <IF>입력 스트림에서 제거하고 다음 중 하나를 남깁니다.

<true>\else<false>\fi

또는

<true>\fi

조건이 거짓이다

TeX는 아무것도 확장하지 않고 \else나타날 수 있는 중첩된 조건을 고려하여 다음 토큰을 찾습니다 . <true>따라서 \else중첩된 \if...\else\fi내부 에 속하는 항목은 <true>건너뜁니다. 이 경우에도 확장은 비어 있으며 이전의 모든 토큰은 \else사라집니다. 일치하는 항목이 없으면 TeX는 어딘가에 있는 것이 더 나은 \else일치 항목을 찾는 것을 중지합니다 . \fi따라서 두 가지 경우에 우리는 다음 중 하나를 얻습니다.

<false>\fi

또는 지점이 없으면 아무것도 아닙니다 \else.

이는 다음 TeX 입력으로 증명됩니다.

\def\showx{\show\x}
\def\showif{\afterassignment\showx
  \expandafter\def\expandafter\x\expandafter}

\showif{\ifvmode<true>\else<false>\fi}
\showif{\ifvmode<true>\fi}
\showif{\ifhmode<true>\else<false>\fi}
\showif{\ifhmode<true>\fi}
\bye

TeX를 실행하면 다음과 같은 기록이 생성됩니다.

This is TeX, Version 3.1415926 (TeX Live 2012)
(./plkfi.tex
> \x=macro:
-><true>\else <false>\fi .
\showx ->\show \x

l.5 \showif{\ifvmode<true>\else<false>\fi}

?
> \x=macro:
-><true>\fi .
\showx ->\show \x

l.6 \showif{\ifvmode<true>\fi}

?
> \x=macro:
-><false>\fi .
\showx ->\show \x

l.7 \showif{\ifhmode<true>\else<false>\fi}

?
> \x=macro:
->.
\showx ->\show \x

l.8 \showif{\ifhmode<true>\fi}

?

다음에 무슨 일이 일어날까요?

  • 확장은 \else일치하는 항목까지 모든 것을 제거 \fi하고 입력 스트림에 아무것도 남기지 않는 것으로 구성됩니다.중첩된 조건문은 이전과 같이 고려됩니다.

  • 확장이 \fi비어 있습니다.

의 역할은\expandafter

이제 우리는 내려놓을 수 있는 기반을 갖게 되었습니다 \expandafter.

일반적인 사용법을 살펴보겠습니다.

\def\@ifundefined#1{%
  \expandafter\ifx\csname#1\endcsname\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}

우리가 원하는 것은 말할 수 있는 것입니다.

\@ifundefined{foo}{T}{F}

따라서 인수를 이름으로 사용하여 작성된 매크로를 비교한 다음 \relax(실제로는 흥미롭지 않은 부분입니다) 참 또는 거짓 분기를 따릅니다.

제거 후에도 <IF>우리는

\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi{T}{F}

이제 TeX는 첫 번째 토큰을 정식으로 확장합니다. 이것은 확장을 촉발 \else하고 여기에서 재미가 시작됩니다.

확장은 \expandafter(가능한 경우) 다음 토큰 이후의 토큰을 확장하고 사라지는 것으로 구성됩니다.따라서 \else위의 규칙에 따라 확장되고 다음이 남습니다.

\@firstoftwo{T}{F}

T그 결과 입력 스트림이 종료됩니다 .

이제 조건이 거짓이라고 가정해 보겠습니다. 그런 다음 은 <IF>까지의 모든 항목과 함께 제거되어 남습니다 \else.

\expandafter\@secondoftwo\fi{T}{F}

이제 \expandafter확장하고 사라지는 작업을 수행합니다 \fi. 따라서 우리는 얻는다

\@secondoftwo{T}{F}

드디어 떠난다 F.

중요 사항

\@ifundefined{foo}{T}{F}우리가 도달할 수 있거나 도달 TF수 없는 경우실행명령: 매크로 확장만 사용되었습니다. 이렇게 하면 \@ifundefined다음 내부에서 유사하게 정의된 매크로를 사용할 수 있습니다 \edef.

\edef\test{\@ifundefined{foo}{T}{F}}

와 동등할 것이다

\def\test{T}

경우가 \foo정의된 경우( \relaxLaTeX에서 평소와 같이 와 동일하지 않음) 또는

\def\test{F}

if는 \foo정의되지 않았습니다(또는 와 동일 \relax).


없이는 어떻게 될까요 \expandafter? 진정한 조건부 TeX를 사용하면 다음과 같은 문제에 직면하게 됩니다.

\@firstoftwo\else\@secondoftwo\fi{T}{F}

그리고 에 대한 두 개의 인수는 and 가 \@firstoftwo될 것입니다 . 이는 유용한 일을 하지 않을 것입니다. 그렇죠?\else\@secondoftwo

마찬가지로, 잘못된 조건에 대해 우리는 다음을 얻습니다.

\@secondoftwo\fi{T}{F}

그리고 다시 일이 잘못될 것입니다.

답변3

이러한 코드의 전체 컨텍스트는 다음과 같은 조건부 매크로에 있습니다.

\def\IfZero#1{%
  \ifnum0=#1\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}

\expandafter형식이 덜 지정된 방식으로 코드를 보면 s가 필요합니다 .

\def\IfZero#1{\ifnum0=#1\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}

(긴 줄에 대해 사과드립니다) TeX 조건부 블록의 구조에 대한 단서가 제공되지 않습니다. 보시다시피 "after" 토큰 \@firstoftwo은 이고 \else그 이후 토큰 \@secondoftwo\fi이며 각각 에 의해 확장됩니다 \expandafter. 이 어리 석음의 목적은 TeX가 확장할 때 전체 조건문을 읽지 않는다는 것입니다 \ifnum. 올바른 true 또는 false 블록을 앞으로 스캔하고 거기서부터 계속됩니다. 또는 입력 스트림에 남아 있습니다 \else! \fi일단 확장되면 TeX는 조건문의 끝까지 스캔하고 입력 스트림의 다음 항목은 다음 항목입니다 \IfZero.

둘 중 하나가 없으면 과 에 \expandafter의해 소비되는 "2개"는 실제로 의도된 것 보다는 다음 매크로 인수, 즉 "두 번째" 및 "세 번째" "인수"로 사용되는 두 개의 다음 매크로 인수입니다. 의 .\@firstoftwo\@secondoftwo\else\@secondoftwo\fi\IfZero

관련 정보