Skip to content

Instantly share code, notes, and snippets.

@zr-tex8r
Created December 11, 2018 13:35
Show Gist options
  • Save zr-tex8r/ccb5c6dc12e4d188799b11b83c1313ce to your computer and use it in GitHub Desktop.
Save zr-tex8r/ccb5c6dc12e4d188799b11b83c1313ce to your computer and use it in GitHub Desktop.
LaTeX: TeXでもアッカーマン関数したい件
\documentclass[a4paper]{article}
\makeatletter %!!!!!!!!!!!!!!!!!!!!!!!!! TeX code BEGIN
%% 変数
\newif\ifmy@ok % 真偽値の返り値専用のスイッチ
\let\my@ret\relax % トークン列返り値専用のマクロ
\newcount\my@m
\newcount\my@mm
\newcount\my@n
\newbox\my@box
\newtoks\my@toks
%% 構築子
% \my@Num{<n>} : 整数n
% \my@Fun{<m>}{<n>} : Ack(m,n)
\def\my@@Num{\noexpand\my@Num}
\def\my@@Fun{\noexpand\my@Fun}
%% \my@name\my@XXX
% 'XXX'に展開される.
\begingroup\lccode`\?=`\@ \lowercase{%
\gdef\my@name#1{\expandafter\my@name@a\string#1;}
\gdef\my@name@a#1?#2;{#2}
}\endgroup
%% \my@use@print
% 式を印字する状態に移行する.
\def\my@use@print{%
\let\my@Num\my@print@Num
\let\my@Fun\my@print@Fun}
\def\my@print@Num#1{#1}
\def\my@print@Fun#1#2{A(#1,#2)}
%% \my@use@eval
% 式を一段評価する状態に移行する.
% この状態で構築子を実行すると \my@ret に一段評価した結果の式を
% 表す値が代入される.
\def\my@use@eval{%
\let\my@Num\my@eval@Num
\let\my@Fun\my@eval@Fun}
% 数値mの場合
\def\my@eval@Num#1{%{<m>}
\def\my@ret{\my@Num{#1}}}
% Ack(X,Y)の場合 (X,Yは式)
\def\my@eval@Fun#1#2{%{<X>}{<Y>}
\my@eval@Fun@a#1*;#2*;}% {}を外す
%※'*'はダミーで, 後で除去される
\def\my@eval@Fun@a#1#2;#3#4;{%\X...*;\Y...*;
\csname my@eval@Fun@@\my@name#1@\my@name#3\endcsname#2;#4;}
% Ack(m,n) (m,nは数値)
\def\my@eval@Fun@@Num@Num#1*;#2*;{%{<m>}*;{<n>}*;
%※#1,#2の{}は外れるこに注意
\my@m=#1\relax \my@n=#2\relax
\ifnum\my@m=\z@ % Ack(0,_)
\advance\my@n\@ne
\edef\my@ret{\my@@Num{\the\my@n}}%
\else\ifnum\my@n=\z@ % Ack(_,0)
\advance\my@m\m@ne
\edef\my@ret{\my@@Fun{\my@@Num{\the\my@m}}{\my@@Num{1}}}%
\else % Ack(_,_)
\my@mm\my@m \advance\my@m\m@ne \advance\my@n\m@ne
\edef\my@ret{%
\my@@Fun{\my@@Num{\the\my@m}}{%
\my@@Fun{\my@@Num{\the\my@mm}}{\my@@Num{\the\my@n}}}}
\fi\fi}
% Ack(m,Ack(X,Y)) (mは数値)
\def\my@eval@Fun@@Num@Fun#1*;#2#3*;{%{<m>}.;{<X>}{<Y>}*;
% Ack(X,Y) の一段評価を求める(結果は \my@ret)
\my@eval@Fun{#2}{#3}%
% \my@ret の内容のトークン列を \my@toks に代入する
\my@toks\expandafter{\my@ret}%
\edef\my@ret{\my@@Fun{\my@@Num{#1}}{\the\my@toks}}}
%% \my@use@isnum
% "式が単なる整数であるか"を判定する状態に移行する.
% この状態で構築子を実行するとスイッチ my@ok に結果を返す.
\def\my@use@isnum{%
\let\my@Num\my@isnum@Num
\let\my@Fun\my@isnum@Fun}
\def\my@isnum@Num#1{\my@oktrue}
\def\my@isnum@Fun#1#2{\my@okfalse}
%%<*> \Ack{<m>}{<n>}
% 公開マクロ.
\def\Ack#1#2{%
% 元の式構造の値を \my@expr に代入.
% (#1, #2の値を評価しておく.)
\my@m=#1\relax \my@n=#2\relax
\edef\my@expr{\my@@Fun{\my@@Num{\the\my@m}}{\my@@Num{\the\my@n}}}%
% "(元の式)"を印字した結果を \my@box に入れる.
\my@use@print \setbox\my@box\hbox{$\my@expr$}%
% \my@expr を一段評価する.
\my@use@eval \my@expr \let\my@expr\my@ret
% 1行目"(元の式)=(今の式)"を印字する.
\par\noindent \copy\my@box
\my@use@print ${}=\my@expr$%
\my@Ack@loop}
\def\my@Ack@loop{%
% \my@expr を一段評価する.
\my@use@eval \my@expr \let\my@expr\my@ret
% "(今の式)"を左側の空きを入れて印字する.
\par\noindent \hskip\wd\my@box
\my@use@print ${}=\my@expr$%
% 式構造がNumであるか検査する.
\my@use@isnum \my@expr
\ifmy@ok\else % Numでないならばループ
\expandafter\my@Ack@loop
\fi}
\begin{document}
\Ack{3}{1}
\end{document}
@zr-tex8r
Copy link
Author

記事:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment