TeXにおける制御綴の引数の個数について

TeXにおける制御綴の引数の個数について

- 匿 名 の投稿
返信数: 14
先日知人から「LaTeX2eマクロ作法(藤田眞作著)」を譲って頂く機会に恵まれまして現在少しずつ消化しているのですが、疑問点を調べたり自分なりに試してみても解決できなかったので投稿いたします。

p.33以降の2・3「複数個の引数」にて\trikaeというマクロをもとにして二番目の中括弧の引数を省略したときや引数に制御綴を与えたときの展開やその対処法などについて触れられています。そこに書かれている内容は理解した(と思う)のですが、「引数が2つ与えられたときはそれらを入れ替え、引数が1つのときは引数をそのまま表示する」といったマクロは作れないでしょうか? つまり、書籍中で出てきた引数を例にとると
\TRIKAE{ABC}{DEF} -> DEFABC
\TRIKAE{ABCDEF} -> ABCDEF
と出力されるようなマクロを定義することは可能でしょうか?(書籍中の\Trikaeなどと同様に\trikaeを用いてでもそうでなくても構いません。)

一応こちらに\trikaeの定義を書いておきますと\def\trikae#1#2{#2#1}です。(http://homepage3.nifty.com/xymtex/fujitas2/yatimata2/v200/yatimata2.pdf#14の1・3以降が同趣旨の文書です。)

これが出来るとかねてから作れたら便利だなと思っていたマクロが定義できそうなので質問させていただきました。
要領を得ない質問になってしまいましたが、何卒宜しくお願いします。
匿 名 への返信

Re: TeXにおける制御綴の引数の個数について

- 帯田 木偶太 の投稿

こんな感じでしょうか。

\documentclass{jarticle}\relax

\makeatletter
\def\TRIKAE#1{%
    \@ifnextchar\bgroup{%
        \TRIKAE@{#1}%
    }{%
        #1%
    }
}
\def\TRIKAE@#1#2{%
    #2#1%
}
\makeatother

\begin{document}

引数が2個の場合:\TRIKAE{ABC}{DEF}

引数が1個の場合:\TRIKAE{ABCDEF}

\end{document}

帯田 木偶太 への返信

Re: TeXにおける制御綴の引数の個数について

- 帯田 木偶太 の投稿

すみません。1箇所、行末をコメントアウトするのが漏れていました。

\makeatletter
\def\TRIKAE#1{%
    \@ifnextchar\bgroup{%
        \TRIKAE@{#1}%
    }{%
        #1%
    }%
}
\def\TRIKAE@#1#2{%
    #2#1%
}
\makeatother

帯田 木偶太 への返信

Re: TeXにおける制御綴の引数の個数について

- 帯田 木偶太 の投稿

LaTeX的に素直なのは、\TRIKAEの引数の一方を
[~]で囲むオプション引数にすることかなあ。


\documentclass{jarticle}\relax

\makeatletter
\newcommand*{\TRIKAE}[2][\@nil]{%
    \def\reserved@a{#1}%
    \ifx \reserved@a \@nnil
        #2%
    \else
        #2#1%
    \fi
}
\makeatother

\begin{document}

引数が2個の場合:\TRIKAE[ABC]{DEF}

引数が1個の場合:\TRIKAE{ABCDEF}

\end{document}

帯田 木偶太 への返信

Re: TeXにおける制御綴の引数の個数について

- 帯田 木偶太 の投稿

私ってバカだ。オプション引数にするんだったら、
次の定義で充分だった。

\documentclass{jarticle}\relax

\newcommand*{\TRIKAE}[2][]{%
        #2#1%
}

\begin{document}

引数が2個の場合:\TRIKAE[ABC]{DEF}

引数が1個の場合:\TRIKAE{ABCDEF}

\end{document}

帯田 木偶太 への返信

Re: TeXにおける制御綴の引数の個数について

- 匿 名 の投稿
帯田さん回答ありがとうございます。ご提示いただいたソースを試したところ希望する出力が得られました。

片方の引数をオプション引数にすることは私も当初考えて実際にその方法では上手くいったのですが,作成したかったマクロにおいてオプショナルな要素がどちらかというと2番目に書くのが直感的・自然なものでしたので,オプション引数にするには違和感を覚えたので質問した次第です。

新たな疑問で恐縮なのですが,一番最初のレスにある\@ifnextchar\bgroupの仕組みが理解できていません。\@ifnextcharは私の中では\@ifnextchar〈判定したい文字〉{一致したときの処理}{一致しなかったときの処理}という書式という認識なのですが,この認識だと引数の個数関係なく\bgroupがマッチしてしまうのでマッチしなかった場合の#1という定義が採用されることがないように思いました。

\@ifnextcharの理解にどこか間違ってるところはありますでしょうか?(そもそもコードを読み違えている可能性もありますが)
匿 名 への返信

Re: TeXにおける制御綴の引数の個数について

- 帯田 木偶太 の投稿

> 新たな疑問で恐縮なのですが,一番最初のレスにある
> \@ifnextchar\bgroupの仕組みが理解できていません。
> \@ifnextcharは私の中では\@ifnextchar 判定したい文字
> {一致したときの処理}{一致しなかったときの処理}という書式という
> 認識なのですが,この認識だと引数の個数関係なく\bgroupが
> マッチしてしまうのでマッチしなかった場合の#1という定義が
> 採用されることがないように思いました。

最初に書いたマクロは、実際には「第2引数が省略されているかどうか」で
条件分岐しているのではなく、「第1引数の後ろに、引数を括る左ブレースが
あるかどうか」で条件分岐しているのです。

\@ifnextcharで第1引数の後ろの文字を調べてそれが\bgroup(これは
左ブレースの別名になっています)と一致するかどうかを見ているのです。

--------

> 片方の引数をオプション引数にすることは私も当初考えて実際に
> その方法では上手くいったのですが,作成したかったマクロにおいて
> オプショナルな要素がどちらかというと2番目に書くのが
> 直感的・自然なものでしたので,オプション引数にするには
> 違和感を覚えたので質問した次第です。

LaTeXで使うコマンドとしては、ブレースで囲む引数を省略可能であるかのように
扱うのは、やはり「行儀が悪い」と思います。
※  LaTeXの標準のコマンドでは、ブレースで囲むのは必須引数、ブラケットで
    囲むのはオプション引数ということで統一が取られていますから。
第2引数をオプションにするというのは、オプションを[~]で囲む仕様に
した場合でも可能ですからその方がいいように思うのですが…

\documentclass{jarticle}\relax

\makeatletter
\newcommand*{\TRIKAE}[1]{%
    \@ifnextchar[{\TRIKAE@{#1}}{#1}%
}
\def\TRIKAE@#1[#2]{%
    #2#1%
}
\makeatother

\begin{document}

引数が1個の場合:\TRIKAE{ABCDEF}ghi

引数が2個の場合:\TRIKAE{ABC}[DEF]ghi

\end{document}

帯田 木偶太 への返信

Re: TeXにおける制御綴の引数の個数について

- 匿 名 の投稿
LaTeX2eマクロ作法のp.20の\@ifnextcharに関する部分は読みましたが,さきほどのコードを見て\@ifnextcharで判定する左ブレースが第一引数を括る左ブレースだと読んでしまっているので,また調べるなり勉強して当該箇所が第一引数の直後(第二引数の左ブレース)を指していることになるのか考えようと思います。

また,オプション引数は引数のうち頭の方に固まっているという先入観があり,お教えいただいたように第一引数を通常の引数,第二引数をオプション引数にすることも出来るというのを恥ずかしなら存じ上げませんでした。ありがとうございました。
匿 名 への返信

Re: TeXにおける制御綴の引数の個数について

- 帯田 木偶太 の投稿

> さきほどのコードを見て\@ifnextcharで判定する左ブレースが
> 第一引数を括る左ブレースだと読んでしまっているので,

\TRIKAEの定義が
    \def\TRIKAE#1{%
で始まっているので、\@ifnextcharが呼ばれた時点で第1引数(および
それを囲むブレース)は既に食べられてしまっており、
入力ストリームには残っていません。

もし定義が
    \def\TRIKAE{%
で始まっていれば、\@ifnextcharによってテストされるのは、
第1引数を囲むブレースになっていたところです。

帯田 木偶太 への返信

Re: TeXにおける制御綴の引数の個数について

- 匿 名 の投稿
>\TRIKAEの定義が
> \def\TRIKAE#1{%
>で始まっているので、\@ifnextcharが呼ばれた時点で第1引数(および
>それを囲むブレース)は既に食べられてしまっており、
>入力ストリームには残っていません。

というのはなんとなく理解できましたが,\defの書式上{}内に定義を書く前に#nの形で引数の個数を書かざるを得ないので,第一引数をオプションにする場合は制御綴名の直後に\@ifnextchar[を書く必要性と#1#2...の位置とが干渉するのではと感じました。
(今回のマクロでは偶然\newcommand{\trikae}[2][\relax]{#2#1}という書き方が出来ますが,作ろうとしたマクロの全部が全部このように上手くいくわけでもないので)
匿 名 への返信

Re: TeXにおける制御綴の引数の個数について

- 本田 知亮 の投稿
他のプログラム言語をしってるとまぎらわしいのですが・・・・
TeXのマクロは「徹頭徹尾置き換え」という認識でいないと
混乱します.
「関数」とか「サブルーチン」じゃないんです.

\def\hoge#1#2{...}
の#1と#2は引数ではなく
{...}の当該部分への「置換テキスト」なんです.

\hogeがあった場合,「後続の二つの要素」を取得して
それを{...}の中の当該部分に置き換えて
\hogeを「置き換え後の「...」」に変更するんです.

問題は「後続の二つの要素」という怪しげな言葉.
\hoge123
\hoge1{23}
\hoge{1},23
\hoge{1},{23}
\hoge{1}{23}
\hoge{1,2}34
\hoge1,2,3
\hoge(1,2)
いろいろなパターンがありますが,
細かいことをいわなければ
{}で囲まれていればそれを一塊,
そうでなければ一文字を一塊とみなします.

ですので
\def\torikae#1{\@ifnextchar[{\@torikae{#1}}{#1}}
\@torikae#1[#2]{#2#1}

\torikae{A}{B} => AB
\torikae{A}B => AB
\torikae{A}[B] => \@torikae{A}[B] => BA
です.

この手の展開は 
\tracingmacros=1
\torikae{A}{B}
\tracingmacros=0
とするとlogに詳細がでてきますので
それをみると何が起きてるのか覗き込めます.

このオプション云々はlatex.ltxで
\@ifnextcharの定義をおいかけると
面白いかもしれません.
\@ifnextcharの定義の本質は
\futureletですが,
空白の読み飛ばしのための
「コントロールワード」と「コントロールシンボル」の
違いとか展開制御のテクニックがパズルみたいです.



本田 知亮 への返信

Re: TeXにおける制御綴の引数の個数について

- 匿 名 の投稿
本田さん、回答ありがとうございます。
仰っていらっしゃるように他のプログラミング言語の延長でTeXのマクロの処理法(と申すのが適切かはわかりませんが)を考えていたせいで理解できていなかったように思います。

回答を読んで自分で考えたところでは例に挙げていらっしゃいます
\def\torikae#1{\@ifnextchar[{\@torikae{#1}}{#1}}
\def\@torikae#1[#2]{#2#1} %\defがありませんでしたがこういうことですよね?
\torikae{A}[B]
がBAと出力されるのは

(\torikaeではなく\torikae#1が一まとまりとして)\torikae#1が\torikae{A}に置換されて{}内の定義が実行される
-> \trikae{A}の次の文字は[B]の[なので\@ifnextchar[の条件にマッチして\@torikae{#1}すなわち\@torikae{A}になる。(この時点で\def\torikae#1{\@ifnextchar[{\@torikae{#1}}{#1}}の処理が終了)
-> \torikae{A}の後ろにある[B]が上の処理で出てきた\@torikae{A}と合わさって\@torikae{A}[B]となり,\def\@torikae#1[#2]{#2#1}のよって最終的にBAが出力される

という過程を経ているということで宜しいでしょうか?
匿 名 への返信

Re: TeXにおける制御綴の引数の個数について

- 本田 知亮 の投稿
>%\defがありませんでしたがこういうことですよね?
はいそうです.落ちてます

処理のタイミングとか諸々のそういう詳細は抜きにして
おおざっぱに考えます

\torikae{A}[B]

というのは

torikae
{
A
}
[
B
]

という風に分解されます.
#実際はもうちょっといろいろあります

torikae を処理(展開)しようとすると
定義より引数が一個必要です
{ があるので,対応する } までが引数です
そこで,torikae A がおきかわって
@ifnextchar [ { @torikae { A } } { A }
[ 
B
]
になります.
@ifnextcharの行は { A } の次の「もの」と
[ を比較して一致すれば
@torikae { A } に
そうでなければ A に置き換わります
このとき,
比較に使われた「次の行の [ 」は
残ります.今は一致したので
@torikae { A }
[ ←比較に使われたけど消費されないで残る
B
]
となります
これで結局 BA がでてきます

動きとしてはお書きになったご理解の通りですが
主観的には,もっと泥臭いというか
まめまめと置換と考える方が
TeXのマクロを考えるにはいいように感じます.
本田 知亮 への返信

Re: TeXにおける制御綴の引数の個数について

- 匿 名 の投稿
「もっと泥臭いというかまめまめと置換」という表現が分かりやすいというかすっと頭に入ってきて疑問が解決できました。

お二方とも重ねてありがとうございました。
匿 名 への返信

Re: TeXにおける制御綴の引数の個数について

- 匿 名 の投稿
北見 けん さんが このスレッドに「いいね!」しました。
(マクロ関係の話題は好きなので(^^))

↑「いいね!」機能なんてあったらどうでしょうか?