LISP on TeX v1.3
久しぶりの更新はLISP on TeXバージョンアップな話.更新点は次の2つ.
- 環境のバグ修正
- one shot continuationsの実装
詳細を示す.
環境のバグ修正
これは,Twitterやここで示されたバグ.要はローカル変数のスコープがおかしくなってしまっている.
簡単な例を示すと,
\lispinterp{((\lambda (\n) ((\lambda (\n) \n) :1)) 'hoge')}
の結果が:1でなく'hoge'になる.原因はv1.2で追加した,環境をマクロに展開する処理.旧コードは次の通り.
\def\@lisp@expand@env@last{\@lisp@expand@env@last} \def\@lisp@expand@environment#1#2{% \ifx#1\@lisp@expand@env@last \let\@@next\relax \else \expandafter\def\csname @lisp@env@\string#1\endcsname{#2}% \let\@@next\@lisp@expand@environment \fi \@@next}
環境\argi{val1}\argii{val2}...を順次展開していくコードになっているが,環境は内部から順に並んでいるので,この順で展開すると外側の束縛のほうが優先されるという……
そこで,これを次のように修正
\def\@lisp@expand@environment#1#2#3\@lisp@expand@env@last{% \def\@@tmp@lisp@env{#3}% \def\@@tmp{\expandafter\def\csname @lisp@env@\string#1\endcsname{#2}}% \ifx\@empty\@@tmp@lisp@env \let\@@next\relax \else \def\@@next{\@lisp@expand@environment#3\@lisp@expand@env@last}% \fi \expandafter\@@next\@@tmp}
\@@tmpを定義して展開順序を制御するようにした.
one shot continuationsの実装
スタックを陽に扱っていない関係上,一級継続は実装が困難だが,one shot continuations位なら実装できる.実際,TUG2013で実装宣言していたので,このv1.3に導入した*1.
one shot continuationsは,要はJavaなどの言語における例外処理みたいな機能を提供するもの.次のように利用する.
(\callOCC (\lambda (\c) ...))
\callOCCがone shot continuationに必要な継続オブジェクトを生成する関数である*2.\callOCCは一引数関数を引数に取り,その関数を継続オブジェクトに適用する.継続オブジェクトもまた一引数関数で,呼び出すと,以降に書いてある式は評価されず,先の式の評価結果が継続オブジェクトを適用した値になる.なお,継続オブジェクトが適用されなかった場合,クロージャの評価結果が\callOCCの評価結果になる.
コード例を示そう.
\documentclass{article} \usepackage{lisp-on-tex} \begin{document} '\lispinterp{ (\callOCC (\lambda (\c) (\begin (\texprint 'executed') (\c ()) (\texprint 'not executed')))) }' \end{document}
(\texprint 'not executed')が実行されていないことがわかる.もっと複雑な例を見たい場合,v1.3にnqueen.texを追加したので,そちらを見てほしい.
補足
ある程度継続を知っている人向け.この機能は一級継続でないため,継続オブジェクトは\callOCCの実行から抜けると無効になる.抜けた後に継続オブジェクトを何かに適用した場合,その動作は保証されない.