読者です 読者をやめる 読者になる 読者になる

LISP on TeX v1.3

久しぶりの更新はLISP on TeXバージョンアップな話.更新点は次の2つ.

  1. 環境のバグ修正
  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の実行から抜けると無効になる.抜けた後に継続オブジェクトを何かに適用した場合,その動作は保証されない.

*1:実際は5月末くらいに実装が終わっていたが,テストコードの整備をしていたため,CTANへのアップロードを保留していた.今回のバグを受けて,ついでにアップロードしたといった方が正しい.

*2:本当は\call/1ccとか使いたいのだが,/も1もカテゴリーコードの関係上使えない