以二叉树作为参数的宏

以二叉树作为参数的宏

我想要一些以二叉树为参数的宏。对于这些宏来说,二叉树要么是,root要么是{branch1}{branch2}两个二叉树branch1branch2并且这些宏应该以递归方式定义。我的想法是,这样的宏应该看起来像

\newcommand{\macro}[1]{\bintree@induction{#1}{\macro@root{#1}}{\macro@branches{#1}}
\newcommand{\macro@root}[1]{%describes what to do in the case of a root
                            <some code>}
\newcommand{\macro@branches}[1]{%describes what to do in the case of branches.
                                %Can use {\bintree@branchone #1} and {\bintree@branchtwo #1}
                                %here to access the branches
                                <some code>}

\newcommand{\bintree@induction}[3]{
  \ifx{}{\bintree@root #1}
  %the binary tree is of the form {branch1}{branch2}
  #3
  \else
  %the binary tree is of the form root
  #2
  \fi}

%when it finds two branches, it gobbles both of them
\newcommand{\bintree@root}{\@ifnextchar\bgroup{\@bintree@root}{}}
\newcommand{\@bintree@root}[1]{\@ifnextchar\bgroup{\@gobble}{#1}}

%To define the macro recursively, we will usually need to handle the two
%branches. Here's the mechanism that selects them.
%This selects the first branch if there is one; all else it does is irrelevant
\newcommand{\bintree@branchone}{\@ifnextchar\bgroup{\@bintree@branchone}{}}
\newcommand{\@bintree@branchone}[1]{#1\@gobble}

%Gobbles the first branch, takes the second out of its braces
\newcommand{\bintree@branchtwo}{\@ifnextchar\bgroup{\@bintree@branchtwo}{}}
\newcommand{\@bintree@branchtwo}[1]{\@ifnextchar\bgroup{\@@bintree@branchtwo}{}}
\newcommand{\@@bintree@branchtwo}[1]{#1}

但这不起作用。我认为这是因为在参数形式为 的\bintree@root #1情况下 并不是真正空的。我该如何实现这一点?下面我附上了一个需要它的 MWE。在那里我找到了一些解决方法,但我不知道如何以类似的方式通过对二叉树进行归纳来定义宏。所以我的问题是:#1{branch1}{branch2}我怎样才能正确地执行宏\bintree@induction

如果有人知道解决这个问题的不同方法,我也会非常高兴。我感觉我的代码非常笨拙,因为过度使用了所有的@'。


\documentclass{article}
\usepackage{amsmath}
\usepackage{comment}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% General induction on binary trees.
%%%% This is used for the macro \jhom@dom@wk below only. For the others
%%%% I found an ad hoc method to get things working...

\makeatletter
\newcommand{\bintree@induction}[3]{
  \ifx{}{\bintree@root #1}
  %the binary tree is of the form {branch1}{branch2}
  #3
  \else
  %the binary tree is of the form root
  #2
  \fi}

%when it finds two branches, it gobbles both of them
\newcommand{\bintree@root}{\@ifnextchar\bgroup{\@bintree@root}{}}
\newcommand{\@bintree@root}[1]{\@ifnextchar\bgroup{\@gobble}{#1}}

%To define the macro recursively, we will usually need to handle the two
%branches. Here's the mechanism that selects them.
%This selects the first branch if there is one; all else it does is irrelevant
\newcommand{\bintree@branchone}{\@ifnextchar\bgroup{\@bintree@branchone}{}}
\newcommand{\@bintree@branchone}[1]{#1\@gobble}

%Gobbles the first branch, takes the second out of its braces
\newcommand{\bintree@branchtwo}{\@ifnextchar\bgroup{\@bintree@branchtwo}{}}
\newcommand{\@bintree@branchtwo}[1]{\@ifnextchar\bgroup{\@@bintree@branchtwo}{}}
\newcommand{\@@bintree@branchtwo}[1]{#1}
\makeatother

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newcommand{\jterm}[3]{#1 \vdash #3:#2}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%
%%%% To get a feeling of how the command works, here are a few examples.
%%%% \ctxext{A}{B} will print A.B
%%%% \ctxext{{A}{B}}{C} will print (A.B).C
%%%% \ctxext{{{A}{B}}{C}}{{D}{E}} will print ((A.B).C).(D.E)

\makeatletter
\newcommand{\ctxext}[2]{\@ctxext@ctx #1.\@ctxext@type #2}
\newcommand{\@ctxext}{\@ifnextchar\bgroup{\@@ctxext}{}}
\newcommand{\@ctxext@ctx}{\@ifnextchar\ctxext{\@ctxext@nested}{\@ifnextchar    \ctxwk{\@ctxwk@nested}{\@ctxext}}}
\newcommand{\@ctxext@type}{\@ifnextchar\ctxext{\@ctxext@nested}{\@ifnextchar\subst{\@subst@nested}{\@ctxext}}}
\newcommand{\@@ctxext}[1]{\@ifnextchar\bgroup{\@ctxext@parens{#1}}{#1}}
\newcommand{\@ctxext@parens}[2]{(\ctxext{#1}{#2})}
\newcommand{\@ctxext@nested}[3]{\@ctxext@parens{#2}{#3}}
\makeatother

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%

\makeatletter
\newcommand{\ctxwk}[2]{\langle\@ctxwk@act #1\rangle\@ctxwk@pass #2}
\newcommand{\@ctxwk}{\@ifnextchar\bgroup{\@@ctxwk}{}}
\newcommand{\@@ctxwk}[1]{\@ifnextchar\bgroup{\ctxwk{#1}}{#1}}
\newcommand{\@ctxwk@act}{\@ctxwk}
\newcommand{\@ctxwk@pass}{\@ifnextchar\ctxext{\@ctxext@nested}{\@ifnextchar\subst{\@subst@nested}{\@ctxwk}}}
\newcommand{\@ctxwk@parens}[2]{(\ctxwk{#1}{#2})}
\newcommand{\@ctxwk@nested}[3]{\@ctxwk@parens{#2}{#3}}
\makeatother

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\makeatletter
\newcommand{\jhom}[3]{\jterm{\jhom@dom@ext{#1}}{\jhom@dom@wk{#1}{#2}}{#3}}

%%%% First define \jhom@dom@ext
\newcommand{\jhom@dom@ext}[1]{\@jhom@dom@ext #1}
\newcommand{\@jhom@dom@ext}{\@ifnextchar\bgroup{\@@jhom@dom@ext}{}}
\newcommand{\@@jhom@dom@ext}[1]{\@ifnextchar\bgroup{\@@@jhom@dom@ext{#1}}{#1}}
\newcommand{\@@@jhom@dom@ext}[2]{\ctxext{\jhom@dom@ext@nested #1}{\ctxwk{\jhom@dom@ext{#1}}{\jhom@dom@ext@nested #2}}}

%%%% The later occurences of context extension should be with parentheses
\newcommand{\jhom@dom@ext@nested}{\@ifnextchar\bgroup{\@jhom@dom@ext@nested}{}}
\newcommand{\@jhom@dom@ext@nested}[1]{\@ifnextchar\bgroup{\@@jhom@dom@ext@nested{#1}}{#1}}
\newcommand{\@@jhom@dom@ext@nested}[2]{\@ctxext@parens{\jhom@dom@ext@nested #1}{\ctxwk{\jhom@dom@ext{#1}}{\@jhom@dom@ext@nested #2}}}

%%%% Now define \jhom@dom@wk. Here I don't see how I can do something similar as
%%%% before. Hence try the more general approach that doesn't really work...
\newcommand{\jhom@dom@wk}[2]{\bintree@induction{#1}{\jhom@dom@wk@root{#1}{#2}}
                            {\jhom@dom@wk@branches{#1}{#2}}}
\newcommand{\jhom@dom@wk@root}[2]{\ctxwk{\bintree@root #1}{#2}}
\newcommand{\jhom@dom@wk@branches}[2]{\ctxwk{\jhom@dom@ext{\bintree@branchone #1}}{\jhom@dom@wk{\bintree@branchtwo #1}{#2}}}
\makeatother

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}
The following output

\begin{align*}
& \jhom{\Gamma}{\Delta}{f}\\
& \jhom{{\Gamma_1}{\Gamma_2}}{\Delta}{f}\\
& \jhom{{{\Gamma_{11}}{\Gamma_{12}}}{\Gamma_2}}{\Delta}{f}\\
& \jhom{{\Gamma_1}{{\Gamma_{21}}{\Gamma_{22}}}}{\Delta}{f}
\end{align*}
should be the same as
\begin{align*}
& \jterm{\Gamma}{\Delta}{f}\\
& \jterm{\ctxext{\Gamma_1}{\ctxwk{\Gamma_1}{\Gamma_2}}}{\ctxwk{\Gamma_1}{{\Gamma_2}{\Delta}}}{f}\\
& \jterm{\ctxext{{\Gamma_{11}}{\ctxwk{\Gamma_{11}}{\Gamma_{12}}}}
                {\ctxwk{\ctxext{\Gamma_{11}}{\ctxwk{\Gamma_{11}}{\Gamma_{12}}}}
                       {\Gamma_2}}}
  {\ctxwk{\ctxext{\Gamma_{11}}{\ctxwk{\Gamma_{11}}{\Gamma_{12}}}}{{\Gamma_2}{\Delta}}}{f}\\
& \jterm{\ctxext{\Gamma_1}{\ctxwk{\Gamma_1}{\ctxext{\Gamma_{21}}{\ctxwk{\Gamma_{21}}{\Gamma_{22}}}}}}{\ctxwk{\Gamma_1}{{\ctxext{\Gamma_{21}}{\ctxwk{\Gamma_{21}}{\Gamma_{22}}}}{\Delta}}}{f}
\end{align*}


\end{document}

答案1

下面的语句可能太简单了,不够健壮:

\def\ctxext#1#2{\@ctxext#1.\@ctxext#2}
\def\@ctxext{\@ifnextchar\bgroup{\@@ctxext}{}}
\def\@@ctxext#1#2{(\@ctxext#1.\@ctxext#2)}

然后

\ctxext{A}{B}

\ctxext{{A}{B}}{C}

\ctxext{{{A}{B}}{C}}{{A}{D}}

生产

代码结果

输入中的任何错误都会导致无限递归或“文件在扫描使用时结束” \@@cxext

相关内容