pTeX 3.141592-p3.1.10 (EUC) (Web2C 7.5.4)を使用しています. 奥村先生の本は読みましたが, マクロについて詳細に書いてある本は読んだことがありません.
やりたいこと:
\vector a,b,c,d ;
と書いたときに
\begin{pmatrix}
a \\ b \\ c \\ d
\end{pmatrix}
と展開されるマクロを作りたいです. 但し, 引数はコンマで区切られる任意個の列です. 安直に
\def\vector #1 ;{
\begin{pmatrix}
\@for \i := #1 \do { \i \\ }
\end{pmatrix}
}
としたのでは \vector a,b,c,d ; としたときに最後に空白が入って5列になってしまいます. そこで1列の場合は諦めて
\def\vector #1,#2 ;{
\let\i=X
\begin{pmatrix}
#1 \@for \i := #2 \do { \\ \i }
\end{pmatrix}
}
としてみると (a,X,X,X) となってしまいます. 然し
\def\vector #1,#2 ;{
\let\i=X
\begin{pmatrix}
\@for \i := #2 \do { \i \\ } #1
\end{pmatrix}
}
とすると (b,c,d,a) となり, TeXの挙動がなぜこの様になるのかよく分かりません.
また, http://note.golden-lucky.net/2006/05/latextex-cf.htmlのような文字列置換を使えばよいのではないかとも考えましたが, pmatrixの中では上手くいきませんでした.
期待する解答:
(1) 正しく動くマクロ. 願わくば1列の場合も期待した動作をするもの.
(2) 何故同じような書き方をしても (a,X,X,X) (b,c,d,a) のような違いになるのかを教えていただきたいです.
よろしくおねがいします.
\@for を真似て
% \@for NAME := LIST \do {BODY}{LAST}
で最後の一要素に対してはBODYではなくLASTを実行するような \@for@last を書いてみました. が, 動きません. どこがわるいのでしょうか...
\def\@fornoop@last#1\@@#2#3#4{}
\def\@for@last#1:=#2\do#3#4{\edef\@fortmp{#2}\ifx\@fortmp\@empty \else
\expandafter\@forloop@last#2,\@nil,\@nil,\@nil,\@nil\@@#1{#3}{#4}\fi}
\def\@forloop@last#1,#2,#3,#4\@@#5#6#7{\def#5{#1}\ifx #5\@nnil \else
{\ifx #2\@nnil #7 \else #6 \fi}
\def#5{#2}\ifx #5\@nnil \else{\ifx #3\@nnil #7 \else #6 \fi}
\@iforloop@last #3,#4\@@#5{#6}{#7}\fi\fi}
\def\@iforloop@last#1,#2,#3\@@#4#5#6{\def#4{#1}\ifx #4\@nnil
\let\@nextwhile\@fornoop@last \else
{\ifx #2\@nnil #6 \else #5 \fi}\relax\let\@nextwhile\@iforloop@last\fi\@nextwhile#2#3\@@#4{#5}{#6}}
% \@for NAME := LIST \do {BODY}{LAST}
で最後の一要素に対してはBODYではなくLASTを実行するような \@for@last を書いてみました. が, 動きません. どこがわるいのでしょうか...
\def\@fornoop@last#1\@@#2#3#4{}
\def\@for@last#1:=#2\do#3#4{\edef\@fortmp{#2}\ifx\@fortmp\@empty \else
\expandafter\@forloop@last#2,\@nil,\@nil,\@nil,\@nil\@@#1{#3}{#4}\fi}
\def\@forloop@last#1,#2,#3,#4\@@#5#6#7{\def#5{#1}\ifx #5\@nnil \else
{\ifx #2\@nnil #7 \else #6 \fi}
\def#5{#2}\ifx #5\@nnil \else{\ifx #3\@nnil #7 \else #6 \fi}
\@iforloop@last #3,#4\@@#5{#6}{#7}\fi\fi}
\def\@iforloop@last#1,#2,#3\@@#4#5#6{\def#4{#1}\ifx #4\@nnil
\let\@nextwhile\@fornoop@last \else
{\ifx #2\@nnil #6 \else #5 \fi}\relax\let\@nextwhile\@iforloop@last\fi\@nextwhile#2#3\@@#4{#5}{#6}}
とりあえず
TeX by topicとか
定評のあるマクロの本を読んでから
latex.ltxとかを解析するのが
結局近道なのでしょう
#TeX Bookも必須か
>(2) 何故同じような書き方をしても (a,X,X,X) (b,c,d,a) のような違いになるのかを教えていただきたいです.
私にはなぜこれが「同じような」と言えるのか
さっぱりわからないのですが・・・明らかに
順番が違うから同じには見えないです.
\def\vector #1,#2 ;{
\let\i=X
\begin{pmatrix}
#1 \@for \i := #2 \do { \\ \i }
\end{pmatrix}
}
において\vec a,b,c ;
の展開を追いかける
_はスペース
#1 = a
#2 = b,c_
#1 \@for \i := #2 \do { \\ \i }
は
a \@for \i := b,c_ \do { \\ \i }
という形
まず \def\i{b}に相当することが起こる
のだが!
最初に \\ があるので,ここで表のセルが終わり
この\def\i{b}はなかったことになる
#一般的な言語でいうところの変数のスコープの問題
したがって\let\i=Xが生き残って
a \\ X
に相当する事態になる.
以降,同じことが続いて結局
(a,X,X,X)になるという寸法
次:こっちは当然そうなるとしかいえないような
\def\vector #1,#2 ;{
\let\i=X
\begin{pmatrix}
\@for \i := #2 \do { \i \\ } #1
\end{pmatrix}
}
において\vec a,b,c ;
の展開を追いかける
_はスペース
#1 = a
#2 = b,c,_
まずは
\@for \i := b,c_ \do { \i \\ } a
という形
最初に\iをXに\letしたって
\@forで\iを一回一回再定義するわけだから
結局 \let\i=X は意味がなくて
\@forは素直に実行されて
(b,c,d,a)
です.
=========
マクロの構築は・・・もっと素直にやれば
というか・・・・
\@tforみたいなものを
さらにpmatrix環境のような
ややこしいものの中で触るから混乱する.
a,b,c,dというリストをもらったら
まず,そのリストそのものを
a\\b\\c\\d
に変換して
その文字列をマクロに定義してから
pmatirix環境の中に突っ込めばいいのでは?
さあ,やってみよう
===================
とここまで書いて・・・ふととあるサイトをみたら
もう答えがでてた・・・orz
盗作みたいになってしまった・・・
だが投稿する!(^-^;
TeX by topicとか
定評のあるマクロの本を読んでから
latex.ltxとかを解析するのが
結局近道なのでしょう
#TeX Bookも必須か
>(2) 何故同じような書き方をしても (a,X,X,X) (b,c,d,a) のような違いになるのかを教えていただきたいです.
私にはなぜこれが「同じような」と言えるのか
さっぱりわからないのですが・・・明らかに
順番が違うから同じには見えないです.
\def\vector #1,#2 ;{
\let\i=X
\begin{pmatrix}
#1 \@for \i := #2 \do { \\ \i }
\end{pmatrix}
}
において\vec a,b,c ;
の展開を追いかける
_はスペース
#1 = a
#2 = b,c_
#1 \@for \i := #2 \do { \\ \i }
は
a \@for \i := b,c_ \do { \\ \i }
という形
まず \def\i{b}に相当することが起こる
のだが!
最初に \\ があるので,ここで表のセルが終わり
この\def\i{b}はなかったことになる
#一般的な言語でいうところの変数のスコープの問題
したがって\let\i=Xが生き残って
a \\ X
に相当する事態になる.
以降,同じことが続いて結局
(a,X,X,X)になるという寸法
次:こっちは当然そうなるとしかいえないような
\def\vector #1,#2 ;{
\let\i=X
\begin{pmatrix}
\@for \i := #2 \do { \i \\ } #1
\end{pmatrix}
}
において\vec a,b,c ;
の展開を追いかける
_はスペース
#1 = a
#2 = b,c,_
まずは
\@for \i := b,c_ \do { \i \\ } a
という形
最初に\iをXに\letしたって
\@forで\iを一回一回再定義するわけだから
結局 \let\i=X は意味がなくて
\@forは素直に実行されて
(b,c,d,a)
です.
=========
マクロの構築は・・・もっと素直にやれば
というか・・・・
\@tforみたいなものを
さらにpmatrix環境のような
ややこしいものの中で触るから混乱する.
a,b,c,dというリストをもらったら
まず,そのリストそのものを
a\\b\\c\\d
に変換して
その文字列をマクロに定義してから
pmatirix環境の中に突っ込めばいいのでは?
さあ,やってみよう
===================
とここまで書いて・・・ふととあるサイトをみたら
もう答えがでてた・・・orz
盗作みたいになってしまった・・・
だが投稿する!(^-^;
本田様,
ありがとうございました. 以下の様にしたところちゃんと動作するようになりました.
初めに挙げたサイトの置換でダメだったのでこちらのサイトの方も...と思っていたのが間違いでした.
%%% from http://hisashim.livejournal.com/276024.html
\def\replace@commawithbackslash#1{\ifx#1\end \let\next=\relax \else\ifx#1,\\\else#1\fi \let\next=\replace@commawithbackslash\fi \next}
\def\vector #1 ;{%
\begin{pmatrix}
\replace@commawithbackslash#1\end
\end{pmatrix}
}
なるほどスコープですか. \\がそのような区切りになるというのは初めて知りました. ありがとうございます.
何かマクロ本を購入しようと思います.
ありがとうございました. 以下の様にしたところちゃんと動作するようになりました.
初めに挙げたサイトの置換でダメだったのでこちらのサイトの方も...と思っていたのが間違いでした.
%%% from http://hisashim.livejournal.com/276024.html
\def\replace@commawithbackslash#1{\ifx#1\end \let\next=\relax \else\ifx#1,\\\else#1\fi \let\next=\replace@commawithbackslash\fi \next}
\def\vector #1 ;{%
\begin{pmatrix}
\replace@commawithbackslash#1\end
\end{pmatrix}
}
なるほどスコープですか. \\がそのような区切りになるというのは初めて知りました. ありがとうございます.
何かマクロ本を購入しようと思います.
>\def\replace@commawithbackslash#1{\ifx#1\end \let\next=\relax \else\ifx#1,\\\else#1\fi >\let\next=\replace@commawithbackslash\fi \next}
>\def\vector #1 ;{%
>\begin{pmatrix}
>\replace@commawithbackslash#1\end
>\end{pmatrix}
>}
この定義の場合,
\vector a_{n1}, a_{n2}, \vdots, a_{nn} ;
のようなものはどうなりますか?
# もっと単純な \vector {{aa}} ; を考えたほうが,
# 引用部分の定義の「大雑把さ」がわかりやすいかもしれません.
\@for を使わないなら使わないでも構いませんが,
もう少し「安全な」定義を行ったほうがよいでしょう.
また,「\vector」というのは LaTeX 自身が提供するコマンドですから,
それをユーザ自身で上書き定義するのは勧められません.
>\def\vector #1 ;{%
>\begin{pmatrix}
>\replace@commawithbackslash#1\end
>\end{pmatrix}
>}
この定義の場合,
\vector a_{n1}, a_{n2}, \vdots, a_{nn} ;
のようなものはどうなりますか?
# もっと単純な \vector {{aa}} ; を考えたほうが,
# 引用部分の定義の「大雑把さ」がわかりやすいかもしれません.
\@for を使わないなら使わないでも構いませんが,
もう少し「安全な」定義を行ったほうがよいでしょう.
また,「\vector」というのは LaTeX 自身が提供するコマンドですから,
それをユーザ自身で上書き定義するのは勧められません.
> # もっと単純な \vector {{aa}} ; を考えたほうが,
> # 引用部分の定義の「大雑把さ」がわかりやすいかもしれません.
というのは、
TeX Q & A 56532
http://oku.edu.mie-u.ac.jp/~okumura/texfaq/qa/56532.html
で教えていただいた、
> \expandafter\ifx \@chapapp \appendixname
とした場合に、
> \def\@chapapp{\relax\relax 第}
だと、\ifx の判断が「真」になる、というのとちょっと似てますね。
# それにしても、
# > 期待する解答:
# > (1) 正しく動くマクロ. 願わくば1列の場合も期待した動作をするもの.
# というのは、なかなか大胆なご発言ですね…。
# あと、本田さんが latex.ltx に触れてらっしゃいますが、質問者の方は、
# LaTeX2.09 の頃の latex.tex のほうを参照されてらっしゃるのですか?
> # 引用部分の定義の「大雑把さ」がわかりやすいかもしれません.
というのは、
TeX Q & A 56532
http://oku.edu.mie-u.ac.jp/~okumura/texfaq/qa/56532.html
で教えていただいた、
> \expandafter\ifx \@chapapp \appendixname
とした場合に、
> \def\@chapapp{\relax\relax 第}
だと、\ifx の判断が「真」になる、というのとちょっと似てますね。
# それにしても、
# > 期待する解答:
# > (1) 正しく動くマクロ. 願わくば1列の場合も期待した動作をするもの.
# というのは、なかなか大胆なご発言ですね…。
# あと、本田さんが latex.ltx に触れてらっしゃいますが、質問者の方は、
# LaTeX2.09 の頃の latex.tex のほうを参照されてらっしゃるのですか?