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

レガシーコード生産ガイド

私に教えられることなら

CommonLispのバッククォートとカンマの入れ子が多分わかった

CommonLisp 学習記録

Common Lispでのバッククォートの入れ子の謎 - レガシーコード生産ガイド に対して、

Gauche作者のShiroさんから、以下のわかりやすい記事で反応があったことに気づいた。

http://blog.practical-scheme.net/shiro/20150123-nested-backquote

引用させていただくと

最初のレベル(外側)のバッククオートで式を展開したい場合はこうする: ,',式

最初のレベルでは展開せず、二番目(内側)のバッククオートで展開したい場合はこうする: ,,'式

なるほど、わかりやすい!

しかし、どういった規則で動いているのだろうか?Shiroさんの指針から動きを想像し、仮説を立てると

  • バッククォートのネスト毎に深さが+1されていく
  • アンクォート(カンマ)のネスト毎に深さが-1されていく
  • アンクォートで深さが0になった(現在処理しているバッククォートと対応した)場合、アンクォートは引数を評価する

例えば次のコードの場合

* (defvar hoge 'x)

HOGE
* (defvar fuga 'y)

FUGA
* ``(,',hoge ,,'fuga) ; ※A

`(X ,FUGA)

,',hogeのとき、最初のカンマで深さ1、次のカンマで深さ0となり、hogeが評価される。よって,'xを返す。

,,'fugaのとき、二個目のカンマで(quote fuga)が評価され、,fugaが返される。

これで※A式が返すのは

`(,'x ,fuga)

; 評価すると (x y)

となる。,'xは(quote x)がその場で評価される、つまり単にxと書いてあるのと同じなので、`(x ,fuga)となり、一つ目のバッククォート展開時にhogeを、2つ目の展開時にfugaを評価できる。

と、思うんだけど、英語苦手なのでCLtL2見てもよくわからず、clispのソースを見ながら手で展開したけど複雑すぎて途中でわからなくなってしまった。

ただ R5RSの4.2.6でのサンプルを見ると

`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)           
                ===>  (a `(b ,(+ 1 2) ,(foo 4 d) e) f)

と、ネストのカウントの考え方で合ってるように見える。

感想など

  • 自作の処理系に実装してみて確かめたい。
  • clispのソース、lispで書かれてて参考になる。
  • Shiroさんが翻訳された本全部持ってるし、10年ぶりにハッカーと画家を読んで「やっぱりプログラミング真面目に取り組んでみようかな」と思い直して今こうしてブログを書いているので、反応があってかなり畏れ多い。
  • なのでもし反応があったら見逃したくないんだけど、バックトラックをはてなブログで見る方法がわからない…プロ版じゃないと見れないのかな
広告を非表示にする