LISP on TeX で千反田えるな話(3)
元ネタ:"LaTeXで "千反田える" してみた(1):概略"
さて,LISP on TeX の時間である.
といっても,プログラム的には簡単なので,今回はpTeX限定な命令を使ってやってみたがメイン.漢数字にするマクロ部分に,pTeXプリミティブ\kansujiを使ってみた.
\kansujiは
\kansuji 1234
のようにして使う.結果は「一二三四」に展開される.TeXでいうところの\romannumeralとか\numberと同じ用法.
0,1,...,9に使う文字は設定可能で,デフォルトは〇,一,…,九.この出力に「千」や「百」,「十」を入れるようなマクロを書いた.
結果はこちら
\documentclass{jsarticle} \pagestyle{empty} \usepackage{lisp} \lispinterpl{% (\define \alphlist (\quote ( 'ぜっと' 'えー' 'びー' 'しー' 'でぃー' 'いー' 'えふ' 'じー' 'えいち' 'あい' 'じぇー' 'けー' 'える' 'えむ' 'えぬ' 'おー' 'ぴー' 'きゅー' 'あーる' 'えす' 'てぃー' 'ゆー' 'ぶい' 'だぶりゅー' 'えっくす' 'わい'))) (\define \strofkananum (\lambda (\n) (\ith \n \alphlist))) (\define \ith (\lambda (\n \lst) (\lispif (\= \n :0) (\car \lst) (\ith (\- \n :1) (\cdr \lst))))) (\define \erutaso (\lambda () (\erutasobody :1))) (\define \erutasobody (\lambda (\n) (\lispif (\= \n :1001) () (\begin (\texprint '\tanda') (\texprint (\group (\strOfInt \n))) (\texprint (\strofkananum (\modulo \n :26))) (\lispif (\= \n :1000) () (\texprint '\\')) (\immediatewrite) (\erutasobody (\+ \n :1)))))) (\define \modulo (\lambda (\n \m) (\- \n (\* \m (\/ \n \m))))) } \newcount\cnttanda \def\tanda#1{% \cnttanda#1\relax \advance\cnttanda10000\relax \expandafter\tandawrite\the\cnttanda} \def\tandawrite#1#2#3#4#5{% \if0#2\else\if1#2\else\kansuji#2\fi 千\fi \if0#3\else\if1#3\else\kansuji#3\fi 百\fi \if0#4\else\if1#4\else\kansuji#4\fi 十\fi \if0#5\else\kansuji#5\fi 反田} \begin{document} \noindent\lispinterpl{(\erutaso)} \end{document}
ほぼLISP(またか).出力は元ネタと同じ.
なお,このコードはいつもどおりリポジトリにおいておいた.
LISP on TeX でマンデルブロな話
LuaTeXならマンデルブロ集合も書ける。
いや,e-pLaTeX でもいけるはずだ.もっと言えば,LISP on TeX で記述できるはずだ.
というわけで書いてみた.精度は時間がかかるのでだいぶ抑えているけど.
以下ソース
\documentclass[a3paper,landscape]{jsarticle} \usepackage[dvipdfm,margin=1pt]{geometry} \usepackage{lisp} \lispinterpl{% (\define \maxloop :100) (\define \scale :100) (\define \limitr (\* :2 \scale \scale)) (\define \sq (\lambda (\x) (\/ (\* \x \x) \scale))) (\define \isMandell (\lambda (\a \b \k \x \y) (\lispif (\< \maxloop \k) /t (\lispif (\< \limitr (\+ (\sq \x) (\sq \y))) /f (\isMandell \a \b (\+ \k :1) (\+ \a (\sq \x) (\- (\sq \y))) (\+ \b (\/ (\* :2 \x \y) \scale))))))) (\define \drawMandell (\lambda (\a \b) (\lispif (\isMandell \a \b :0 :0 :0) (\begin (\texprint '*') (\immediatewrite) ) (\begin (\texprint '-') (\immediatewrite) )))) (\define \modulo (\lambda (\n \m) (\- \n (\* \m (\/ \n \m))))) (\define \loopMandell (\lambda (\n) (\lispif (\= \n (\* :4 \scale \scale)) % test (\* :4 \scale \scale) () (\begin (\drawMandell (\- (\modulo \n (\* :2 \scale)) \scale) (\- (\/ \n (\* :2 \scale)) \scale)) (\lispif (\= (\modulo \n (\* :2 \scale)) (\- (\* :2 \scale):1)) (\texprint '\\') ()) (\loopMandell (\+ \n :1)))))) } \begin{document} \fontsize{5pt}{0pt}\selectfont\ttfamily\noindent \lispinterpl{(\loopMandell :0)} \end{document}
LISPじゃねーかw
ソース自体は,リポジトリに置いてある.勇気のあるひとは実行して欲しい.
実行結果はこちら*1.アスキーアート出力なので,アスペクト比がおかしいけど,計算自体はできている.
一応,ログファイルのメモリ使用量もつけてみる.
Here is how much of TeX's memory you used: 1523 strings out of 494059 15752 string characters out of 3159691 112278 words of memory out of 3000000 5008 multiletter control sequences out of 15000+200000 9102 words of font info for 41 fonts, out of 3000000 for 9000 750 hyphenation exceptions out of 8191 39i,4n,80p,192b,229s stack positions out of 5000i,500n,10000p,500000b,50000s
ちなみに,私の実行環境(W32TeX (2012/2/4),Core 2 Quad 2.4GHz,4GB memory)での計算時間は 130 [min] ほどでした.
*1:ページ番号入れっぱなしだったのでトリミングしてある
これでいいのかなぁ?
TeX芸人検定への解答.
\catcode`@=11 \def\xx@q@end{\xx@q@@end} \def\xx@q@head{\afterassignment\xx@q@calc\let\xx@q@temp= } \def\length#1{\xx@q@head#1\xx@q@end} \def\xx@q@calc{% \show\xx@q@temp \ifx\xx@q@temp\xx@q@end \let\xx@q@next\relax \else *\let\xx@q@next\xx@q@head \fi\xx@q@next} \tracingmacros=1 \length{hoge \fuga {group\piyo}} %************** \bye
こーゆー事なのだろうか?
修正その一
そっこーで違うと把握(\edefでこれを使えない.).まじか……
これから卒業論文などでLaTeXを使う人へ向けて
余り書くことがないので,LaTeXの初心者への注意点を書いてみる.
所属研究室での使用状況がわりとひどかったから……
その情報は古くなってないですか?
{\it ...}とかで書体変更はしない方がいい
この書体変更法は昔(LaTeX 2.09)時代のものです.現在では,\textitなどの命令を使うのが一般的です.古い方法では,例えば「イタリックかつボールド」なんて指定をやろうとすると苦労するはずです.もちろん,イタリック体を表示するために$で囲むのは論外です.
EPSに変換しなければいけないという時代は終わった気がする
卒業論文を書く環境では,DVIPDFMxを使ってPDFに変換することが一般的になってきました.LaTeX用のエディタもそのような設定になっているはずです.その環境でわざわざEPSに変換することはほぼ無意味です.PNGやJPEGが使えます.PDFそのものが埋め込めたりもします.DVIOUTやxdviなどがその表示に対応していないだけです.Adobe Readerあたりで見ればちゃんと画像は入っています.
どこから情報を得ればいいのさ?
美文書だったり独習だったりが初心者向けのベストチョイスだと信じています.
版面変更はgeometry.styがいいと思うんだ
我が大学の出身学科では,レポート用のテンプレートが公開されていて,卒業論文でもそれをコピーして使う人が多いようです.更にそれをよくわからないまま改変する奴がいます.特に多いのが,余白などのレイアウト指定を変更する人です.あのテンプレートを含め,よくある方法では版面の変更を\setlengthなどを利用して行います.それはLaTeXの範囲で正しいコードです.しかし,よくわからないまま使うのはおすすめできません.よくわからないエラーが出て,よくわからなものが出来上がります.
それならば,geometry.styを使うのがいいと思うのです.使い方は調べればすぐに出てくるので割愛.
EeePC 901 に Arch いれてみたったー
ちょっとしたお遊びでやったもの.EeePC 901*1に現行のisoを使って Arch Linux を入れるお話.方針は
基本的には ココを見ればいいのだけれど,怠けようとしたりすると詰まるので私が詰まった点をメモ.
UNetBootin が腐っている
UNetBootin に Arch あるじゃんとかいってこれ使うと泣きます.ブートでエラーになりましたとさ.ちなみに iso 落としてきてもダメだった.
/etc/mkinitcpio.conf は書き換えないとダメ
SD に入れる場合のみかもしれない.デフォルトでは usb が入っていないので入れておく.こうしないと SD が見つからないという悲惨な目に遭う.
あとは問題なくいけた.USB からインストールしてデバイスノード名周りで苦労するのはよくあることなので割愛.X はまだ入れてない.
*1:めっさ古い
TeXで競技プログラミングは可能か?
ジャッジシステムないので無理ですが.
というのも残念なので,まずはそもそも解くことができるかについて.問題はAtCoder Regular Contest #005のA,B,C*1.
A
コード
% const data \def\tki{TAKAHASHIKUN} \def\tkii{Takahashikun} \def\tkiii{takahashikun} \def\solve#1.{\ssolve#1 \relax.} \def\rrelax{\relax} \newcount\lovetk \def\ssolve#1 #2.{% \def\cmp{#1}% \def\chkend{#2}% % Is \cmp 'takahashikun' word? \ifx\cmp\tki\advance\lovetk1\fi \ifx\cmp\tkii\advance\lovetk1\fi \ifx\cmp\tkiii\advance\lovetk1\fi \ifx\rrelax\chkend\else % data owari? \ssolve#2.\fi} \read-1to\stdin % read #words \read-1to\stdin % read sentence \expandafter\solve\stdin \immediate\write16{\the\lovetk}% \bye
B
- テーブル作って実装するだけ
コード
% move direction \newcount\dx\dx0 \newcount\dy\dy0 \newcount\x \newcount\y \read-1to\tmp % readline % function set x,y,W \def\setfirstline#1 #2 #3.{% \x#1\relax \y#2\relax \def\W{#3}} \expandafter\setfirstline\tmp. \def\calcW#1#2{\ccalc#1\ccalc#2} \def\ccalc#1{% \if#1R\dx1\fi \if#1L\dx-1\fi \if#1U\dy-1\fi \if#1D\dy1\fi} % function : W -> dx,dy \expandafter\calcW\W\relax \newcount\readline\readline1 % set map data \def\setline#1#2#3#4#5#6#7#8#9{% \expandafter\def\csname data\the\readline1\endcsname{#1}% \expandafter\def\csname data\the\readline2\endcsname{#2}% \expandafter\def\csname data\the\readline3\endcsname{#3}% \expandafter\def\csname data\the\readline4\endcsname{#4}% \expandafter\def\csname data\the\readline5\endcsname{#5}% \expandafter\def\csname data\the\readline6\endcsname{#6}% \expandafter\def\csname data\the\readline7\endcsname{#7}% \expandafter\def\csname data\the\readline8\endcsname{#8}% \expandafter\def\csname data\the\readline9\endcsname{#9}} % read map from stdin \loop\ifnum\readline<10 \read-1to\tmp \expandafter\setline\tmp \advance\readline1 \repeat \newcount\chk \def\buffer{} \readline1 % output \loop\ifnum\readline<5 \edef\buffer{\buffer\csname data\the\y\the\x\endcsname}% \advance\readline1 \chk\x\relax \advance\chk\dx\relax \ifnum\chk<1\multiply\dx-1\relax\fi \ifnum\chk>9\multiply\dx-1\relax\fi \advance\x\dx\relax \chk\y\relax \advance\chk\dy\relax \ifnum\chk<1\multiply\dy-1\relax\fi \ifnum\chk>9\multiply\dy-1\relax\fi \advance\y\dy\relax \repeat \immediate\write16{\buffer} \bye
C
- 幅優先探索で解いた.
コード
\read-1to\stdin % read one line from stdin to \stdin % read H and W \newcount\h \newcount\w \def\readHW#1 #2\relax{% \h=#1\relax \w=#2\relax} \expandafter\readHW\stdin\relax % read map \newcount\loopcnt \newcount\tmpw \newcount\sh \newcount\sw \def\setmap{% \tmpw=0\relax\expandafter\setmapp\stdin\relax} \def\setmapp#1#2{% \expandafter\def\csname map\the\loopcnt:\the\tmpw\endcsname{#1}% \if#1s \sh=\loopcnt \sw=\tmpw \else\fi \ifx#2\relax\def\next{}\else\def\next{\setmapp#2}\fi \advance\tmpw1\relax \next} \catcode`\#=12\relax \loop\ifnum\loopcnt<\h \read-1to\stdin \setmap \advance\loopcnt1\relax \repeat \catcode`\#=6\relax % init deque data \let\Data\relax \edef\deque{\Data{\the\sh:\the\sw,0}} \def\empty{} % function : get topdata to \pos and \brcnt \def\getdata#1{\expandafter\ggetdata\expandafter#1\deque\relax} \def\ggetdata#1\Data#2#3\relax{% \def#1{#2}\def\deque{#3}\parsePosBreak#2\relax} \def\parsePosBreak#1,#2\relax{% \brcnt=#2\relax \def\pos{#1}} % Breadth first search \catcode`\#=12\relax \def\start{s} \def\goal{g} \def\kabe{#} \def\michi{.} \catcode`\#=6\relax %search main \newcount\brcnt \newcount\tw \newcount\th \def\search#1:#2(#3,#4){% \th=#1\relax\advance\th#3\relax \tw=#2\relax\advance\tw#4\relax \expandafter\ifx\csname map\the\th:\the\tw\endcsname\kabe % KABE NO NAKA NI IRU \ifnum\brcnt<2 \advance\brcnt1 % add to tail \edef\deque{\deque\Data{\the\th:\the\tw,\the\brcnt}} \advance\brcnt-1 \fi \else % add to top \edef\deque{\Data{\the\th:\the\tw,\the\brcnt}\deque}% \fi} \def\pos{} \def\checked{true} \def\solve{\let\next\relax% \ifx\deque\empty\immediate\write16{NO} % empty! \else \getdata\data % get top data \expandafter\ifx\csname flag\data\endcsname\checked % checked before -> continue \let\next\solve \else\expandafter\ifx\csname map\pos\endcsname\relax % out of map \let\next\solve \else % check \expandafter\let\csname flag\data\endcsname\checked \expandafter\ifx\csname map\pos\endcsname\goal % GOAL now \immediate\write16{YES}\let\next\relax \else \expandafter\search\pos(0,1)% \expandafter\search\pos(0,-1)% \expandafter\search\pos(1,0)% \expandafter\search\pos(-1,0)% \let\next\solve \fi \fi\fi \fi\next} \solve \bye
現在の LISP on TeX における環境の実装と問題点
今日は LISP on TeX (https://bitbucket.org/hak7a3/lisp-on-tex) の環境の実装および問題点について.
現状,LISP on TeX *1 の環境は次のようなトークン列になっています.
\keyi{valuei}\keyii{valueii}……\keyn{valuen}
対応を追加する際には,トークン列の先頭にペアを書き込む形になっています.\keyhogeに対応する値を引き出す際は,マクロの書式指定文字列を使ってとリ出すようにするといけます.実際,LoT の初期の(裏)目的のひとつは,「TeX でまともなプログラミングをするためのライブラリが作成できたら嬉しいな」*2だったりしました.その影響で,環境周りの制御綴りには@が入っていなかったりします.
さて,これを使って LoT の環境を構築した時の問題点です.それは
- set! の実現が困難
- letrec の実現も困難
の二点です.これは,環境が「ポインタ」的に扱われていないことが要因です.set! では環境を共有しているすべてのものに変更が波及しないといけませんが,クロージャが環境をトークン列として持っているため,どの部分で他と共有しているかを判断できません.また,letrec の場合はクロージャが自身への参照を持つこととなり,環境が無限列となり崩壊します.
例外的に,大域環境は \@globalenv というマクロで定義され「ポインタ」的に扱える関係上,これらの制限がありません*3.
解決方法的な何か
値を一段「ポインタ」的な何かに変更
コード例
\keyi{indexi}\keyii{indexii}……
制御綴り [env@indexi]*4が valuei に展開されるように定義します.index は一意になるようなものを振ります.現状の LoT の cons セルがこれに近い実装になっています*5.今の実装をほとんど変えずにいけるけど,いい手だと思えない.
思い切って,リスト構造にする
こんな感じ
\envi -> \envii\keyi{valuei} % next, key, value
このように定義した \envi を持ち歩く.環境への追加に関して少し考慮すべきな点が*6.
さーて,どうしようかな……
おまけと言う名の私信 Twitter の反応
*1:以下,長いのでLoT
*2:そもそも近代的な言語には程遠いんだから無理という観点は除く
*3:だから,bitbucketのサンプルでは再帰関数が動いている
*4:伝統に則り,制御綴りは四角で囲んで表記してみました.わからない人は \csname env@indexi\endcsname と思っていただけると?
*5:set-car!とかが簡単
*6:実力の無さとも言う