roswellで開発中プロジェクトを簡単にloadする
開発中のプロジェクトを簡単にloadできるようにするスクリプトを書きましたが、改訂の途中です。
- 2017/05/25 追記: roswellのサブコマンドになりました。詳細はroswellサブコマンドへの道参照
動機
ぼくはrosaやinquisitor等々ライブラリを改修するときにslimeからql:quickload
するため、~/roswell/local-projects/
にライブラリの.asd
ファイルにシンボリックリンクを張って開発をしています。どうもASDFはシンボリックリンクを辿ってくれるようなので、便利です。
ところで一方、roswellのリリースがあるたびに~/.roswell
を消すことにしています。理由はなんとなくです。そうすると、だいたい一ヶ月に一回くらい~/.roswell
を消していることになりますが、~/.roswell/local-projects
の中身も消えてしまうので、その度にシンボリックを張り直しています。
それってめんどくさい。
そして、それって自動化できるなと今日(ついに!)気付いたので、それを自動化してみました。
最初のアプローチ
……というようなことをシェルスクリプトで書いてみました。どうやっているかは中を覗いてみてください。
dotfiles/ros-local.sh at 747385a4e6900484eb2f583196dcf78cd846481c · t-sin/dotfiles · GitHub
Usageはこんなかんじ。
cat <<EOF localprj.sh COMMAND [PARAMS...] Maintain roswell local-prpjects. localprj.sh see in ROSWELL_DIR to search roswell's local projects. Also it see in CODE_DIR to search local codes. COMMANDS: show show present configuration. local list asd files in local-projects. list list available asd files in code directory. put ASD_NAME make symbolic link from ASD_FILE into roswell local-projects. del ASD_NAME unlink ASD_FILE from roswell local-projects. EOF
S式への道
仕事中になにやっとんねんという感じですがお昼休みなのでだいじょうぶです。もしかしたら車輪を再発明したかもしれないのでツイートしてみたところ、roswell作者の佐野さんからご意見が。
@sin_clav 便利そう。symlinkがそこそこ使いにくいosもあるので、ros scriptで書きませんか?asdf:load-asdを呼ぶlispのソースを(ql:qmerge "local-init/")以下に生成するのでほぼ等価だと思うのでどうでしょうか?
— Masatoshi SANO (@snmsts) 2017年5月24日
ql:qmerge
とかasdf:load-asd
とかあるんですね。初めて知りました。というわけで、roswellスクリプトとして書きなおしてみました。シェルスクリプト版が存在したのは正味一時間程度でした。
さようなら、ros-local.sh
。
ありがとう、ros-local.sh
。
そして、
_人人人人人人人人人人人人人人_ > ようこそ! Common Lisp! <  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄
dotfiles/ros-tap.ros at 751b5298fed6f1482731d6c81b70c24335184489 · t-sin/dotfiles · GitHub
え、しごと? ちょっとストレスが溜まってたし、忙しくなかったからゆるして……。
roswellサブコマンドへの道(追記)
この記事を公開後、佐野さんからこのようなご意見をいただきました。
@sin_clav 本体に取り込まなくても、けっこう場当たり的に拡張できるようにしたので、密な結合が必要そうな物以外は本体に取り込むのをためらいます。 https://t.co/9JrdFFLjUZ
— Masatoshi SANO (@snmsts) 2017年5月24日
なんと、roswellのサブコマンドは自前で追加が可能だったんだよ!!
な、なんだってー!
というわけで、プロジェクトに切り出しました。ライブラリ開発してるとけっこう便利そうなので使ってみてください。プルリクやご意見大募集中です。
おわりに
eval
必要かしらん- 出力ファイルが大文字なの、カッコわるい気がする
roswellにぷるぷるリクエストを出して、rosコマンドに入れてもらうのアリでは?- roswell入れてもらわなくても拡張可能でした
package-inferred-systemに期待したもの
これまでのあらすじ
package-inferred-systemは、pakageのinferred-systemである。
なんだか体がだるい感じのぼくはこころに学びを沁みわたらせるため、ライブラリのパッケージをすっきりと書くことはできないか考えてみようと思った。Common Lispを書いていてディレクトリ構成とパッケージ構造を同じにしたいとき、以下の2点が面倒だ:
- パッケージ名をわざわざパッケージ定義に書くこと
- パッケージ名とディレクトリ名を一致させること
- パッケージ構造を変えたとき、変更が漏れやすい
そこでぼくは、1ファイル1パッケージのスタイルでプログラミングできるらしいpackage-inferred-systemを試してみようと考えたのだった──
TL;DR
package-inferred-systemは、ディレクトリ構造からパッケージ名を決定するためのものではない。
package-inferred-system とは
package-inferred-systemは、Common LispのASDFの拡張機能です。ASDFはCommon Lispにおいてライブラリ定義・読み込みを司る、ほぼ標準のアドオンです。Pythonでいえば、setup.py
(定義)とdistutilsに相当します。それにしてもPythonにおいて。「ほぼ標準」というのは、Common LispはANSIで言語仕様が定められていますが、ASDFはその中には含まれておらず、しかしだいたいの処理系に始めからバンドルされているので準標準的である、という意味です。モジュール
とパッケージ
は別のものを指す言葉だったのかー*1、知らなかったぜ 😎
ASDFの公式ドキュメントに拠れば、package-inferred-systemとは
Starting with release 3.1.2, ASDF supports a one-package-per-file style of programming, whereby each file is its own system, and dependencies are deduced from the defpackage form (or its variant uiop:define-package).
ASDF Manual: The package-inferred-system extension
とのことです。この機能に対して、誤った期待をしていたために、いろいろもやもやさせられた、というのがこの記事の要旨です。
期待していたもの
ぼくがone-package-per-file
という言葉で期待したのは、Pythonのモジュールシステムのようなものでした。つまり、次に述べるようなものです。
Pythonでは、ソースコードのファイル自体がモジュールです。なので、以下のようなa.py
とb.py
があるディレクトリでインタプリタを立ち上げて
# a.py s = 's in module a'
# b.py s = 'string in module b'
>>> import a >>> a.s 's in module a' >>> import b >>> b.s 'string in module b'
ということができるようになる、と思っていました。つまり、Common Lispで次のようなことができるようになるのだ、と。
;;;; a/hoge.lisp (defun foo () (format t "No defpackage!!~%"))
CL-USER> (use-package :a/hoge) CL-USER> (a/hoge:foo) "No defpackage!!
いや、export
してないじゃん、という意見はごもっともですが。export
は手でする必要はあるにしろ、ディレクトリ構造と一致したdefpackage
を書かなくなるなら、それは楽だなあと思っていました。
実際のpackage-inferred-system
じゃあ、実際にはどうだったか。
こうでした:ファイルパスと一致したdefpackage
をしておけば、ASDF側でディレクトリ構造からパッケージ名を想像して読み込んでくれる。
つまり、冒頭に挙げた問題点
- パッケージ名をわざわざパッケージ定義に書くこと
- パッケージ名とディレクトリ名を一致させること
は解決してくれません!! 残念!!!
ただ、便利な点がまったくないかというとそういうことでもありません。以前ならば.asd
フィアルに書いていた依存関係を、package-inferred-systemが内挿してくれるために、書かなくてよくなります。たとえばpackage-inferred-systemでない以下のようなsystemがあったときに、
;; hoge.asd (defsystem hoge :depends-on (:alexandria) :components ((:module "src" :components (:file "fuga") (:file "core") (:file "hoge" :depends-on ("fuga" "core"))))
以下のように書くことで、:components
節がまるまる不要になります。
;; hoge.asd (package-inferred-system) (defsystem foo :depends-on ("alexandria" "hoge/hoge"))
ただし、各パッケージに該当するファイルには、それぞれ以下のようなdefpackageをする必要があります(長くなるのでin-package
は省略しました)。
;; hoge/hoge.lisp (defpackage :hoge/hoge (:use :cl :hoge/src/core :hoge/src/fuga))
(defpackage :hoge/src/fuga (:use :cl))
;; foo/src/core.lisp (defpackage :hoge/src/core (:use :cl))
つまり、ディレクトリ構造と:use
などからパッケージの依存関係を推測してくれるんだよ…!!
おわりに
package-inferred-systemはone-pakcage-one-fileのスタイルを支援する機能です。しかしそれは、パッケージ名を自動で内挿してくれる機能ではありません。ディレクトリ構造とインポートの記述からパッケージ依存関係を推測してくれる機能です。
この機能の恩恵を特に得やすいのは、パッケージ数(=ファイル数)が多く、ディレクトリ構造が複雑なプロジェクトです。そういったプロジェクトは.asd
ファイルとディレクトリ構造を手動で一致させる手間が増えるため、defpackageさえちゃんとしていれば、依存関係を書かなくていいpackage-inferred-systemはかなり有用でしょう。
こうして、package-inferred-systemへの溜飲が下がり、これからは使ってみようかなあという気になったのであった。
Lispエイリアン壁紙をつくりました2
Lisp界のマスコット、Lispエイリアンの壁紙をまたつくりました。
http://f.hatena.ne.jp/t-sin/20170513011545 オリジナルサイズ
背景
以前Lispエイリアンの壁紙をつくりました。
でも、黒いのがほしかったので、またつくりました。
もっとクールなやつを、だれかつくってください!! だれか!!!
祝! Rosaバージョン1.0!
最近つくったrosaというライブラリ・ツールのバージョンを1.0にしました。
テキストデータに、書きやすく見た目を邪魔しない形式で、メタデータを埋め込むための言語です。実際にどんなものかというのは、以下の記事に書きました。
名前は「ろさ」「ろーざ」のどちらかで読んでください。元ネタ的には「ろーざ」のようですが、ぼくは「ろさ」って読んでます。ラテン語。
Ver. 1.0になって増えた機能
以下のことをしました:
- ラベルには半角スペース以外の文字を使えるようになった
- リスト省略表記
リスト省略表記
リスト省略表記は、ラベルを並べてリストを表現するという方法のシンタックスシュガーです。以下の2コードが等しい感じです。
;; 略記じゃないベタ書き CL-USER> (with-input-from-string (in " :tag lisp :tag common-lisp :tag programmnig ") (rosa:peruse-as-plist in)) (:|tag| #("lisp" "common-lisp" "programmnig"))
;; リスト省略表記 CL-USER> (with-input-from-string (in " :tag> - lisp - common-lisp - programmnig ") (rosa:peruse-as-plist in)) (:|tag| #("lisp" "common-lisp" "programmnig"))
これだけです。
以下、回想
アイデア自体は2011年ごろからあり、今でいう静的サイトジェネレータの記事データを表現するために考えたものでした。当時はまだLispは興味があるだけだったので、rosaをC++で実装しようした形跡があり、手元の旧プロジェクトのコミットログにはそれが残っています。就職してからCommon Lispで実装しだして一旦完成、そのあとに謎の軽量マークアップ言語機能が乗ったりしたあと放置。
なんとか実行可能バイナリをつくったこともありました。Common Lispの実行可能バイナリのビルト方法がよくわかっていなかったので、その時偶然できたバイナリをわりと最近まで使い続けてました。
マークアップ言語部分は、あおぞら文庫の構文や組版本を参考にしつつ、シュッとした言語になればいいなーと妄想しています。
苦節もうすぐ七、八年か。考えた当時(大学生!)はCommon Lispでこんなにコード書いてるとは思いませんでした。ゲームでもつくんだろうなって思ってました。どうしてこうなったのか。
これからも誰の役に立つのかよくわからないプログラムをCommon Lispで書いていけたらいいなあー。
Seriesで響け!ユーフォニアム!
Series触る触ると言ってたのに触ってなかったので、手始めに響けユーフォニアムをseriesでやってみました。
2017/4/29 追記
「妙なwarningが出てしまうこと」について、以下の記事の反応をいただきました。
この記事ではapply
でseriesをつくっているために、seriesの最適化のしくみにこの記事のコードを載せることができなかったのが原因なのでしょう。
Seriesとは
Seriesは、Common Lispに導入されかけたけど時間がないので却下されたという、繰り返し構造を宣言的に表現するためのしくみです。Seriesを使えばHaskellやClojureのような、関数型言語っぽいデータ処理ができそうな感じです。
仕様は"Common Lisp the Language 2nd Edition"の付録Aに書かれています。英語ならウェブでも読めます。
また日本語の説明は次のページが詳しいです。
ちなみに使うときはこんな感じです。
CL-USER> (ql:quickload :series) CL-USER> (use-package :series) CL-USER> (collect 'string (subseries (apply #'series (coerce "グソクムシ" 'list)) 0 20)) "グソクムシグソクムシグソクムシグソクムシ"
響け!ユーフォニアムとは
アニメの名前で、ぼくは見ていませんが、ちょっと前にtwitterでこんな遊びがはやっていました。
その時期にぼくもCommon Lispのformat
関数でやってみたりしたので、とりあえずseriesの入門としてやってみるのにいいのではと思った次第です。
redditのlisp_jaが、似た問題でちょっと盛り上がってた時期がありました。
結果…
Seriesのままならこんなかんじ:
CL-USER> (let* ((str "響け!ユーフォニアム") (len (length str))) (mapping ((i (scan-range :from 0 :by 1 :upto len))) (collect 'string (subseries (apply #'series (coerce str 'list)) i (+ i len))))) #Z("響け!ユーフォニアム" "け!ユーフォニアム響" "!ユーフォニアム響け" "ユーフォニアム響け!" "ーフォニアム響け!ユ" "フォニアム響け!ユー" "ォニアム響け!ユーフ" "ニアム響け!ユーフォ" "アム響け!ユーフォニ" "ム響け!ユーフォニア" "響け!ユーフォニアム")
問題に沿って標準出力に出力するならこうか:
CL-USER> (let* ((str "響け!ユーフォニアム") (len (length str))) (iterate ((i (scan-range :from 0 :by 1 :upto len))) (format t "~a~%" (collect 'string (subseries (apply #'series (coerce str 'list)) i (+ i len)))))) 響け!ユーフォニアム け!ユーフォニアム響 !ユーフォニアム響け ユーフォニアム響け! ーフォニアム響け!ユ フォニアム響け!ユー ォニアム響け!ユーフ ニアム響け!ユーフォ アム響け!ユーフォニ ム響け!ユーフォニア 響け!ユーフォニアム NIL
関数型っぽくシーケンス処理を書けるので、カッコいいと感じました。これからも使っていきたいです。
疑問
上のコード、実行するたびに以下のようなwarningが出るんですよね。なんとかならないものか。
; in: LET* ((STR "響け!ユーフォニアム") (LEN (LENGTH STR))) ; (ITERATE ((I (SCAN-RANGE :FROM 0 :BY 1 :UPTO LEN))) ; (FORMAT T "~a~%" ; (COLLECT 'STRING ; (SUBSERIES (APPLY #'SERIES #) I (+ I LEN))))) ; ; caught WARNING: ; Warning 28 in series expression: ; (COLLECT 'STRING (SUBSERIES (APPLY #'SERIES (COERCE STR 'LIST)) I (+ I LEN))) ; Non-series to series data flow from: ; (APPLY #'SERIES (COERCE STR 'LIST)) ; to: ; (SUBSERIES (APPLY #'SERIES (COERCE STR 'LIST)) I (+ I LEN)) ; ; compilation unit finished ; caught 1 WARNING condition
Rosaに謎のシリアライズ機能が登場
先日こんなものが完成しました。
まあ用途や有用性の不明な、なんだかよくわからんプロジェクトだとぼく自身も思うわけですが、なんなんでしょうね(ぼく自身ではわりと使ってます)。
Rosaについて
Rosaとは
文字列に名前を付けて、それをプレーンテキストで表現できる言語です。そして、それをパースするライブラリ・コマンドでもあります。
機能の弱いJSONとかYAML、のような感じと見做すこともできるかもしれません。
「タイトル」「著者名」「更新日付」「本文」「あとがき」などのテキスト情報をひとつのファイルに、人間が書きやすい構文(=インデントや妙な括弧がない)で書き表せる言語です。小説とかブログの一記事とか、そういうのを一ファイルで書くのに使おうと思ってつくりました。
ちなみに、中のテキストのマークアップは感知しないので、別の言語(Markdown、reStructured text、あおぞら文庫形式)を選択できます。というかしてください。
Rosaでパースしたテキストデータ
Rosaで定められた形式で、key-value的なデータを表すことができます。たとえば、ポケモンとその登場作品の対応、とか。
CL-USER> (setf pokemon " :diamond-pearl ブイゼル :sun-moon モクロー :sun-moon クワガノン") CL-USER> (with-input-from-string (in pokemon) (rosa:peruse-as-plist in)) (:|diamond-pearl| #("ブイゼル") :|sun-moon| #("モクロー" "クワガノン"))
テキストをパースすると、rosa:peruse
でハッシュテーブル、rosa:peruse-as-plist
でプロパティリストになります。これから所望のデータを抜き出して、wc -m
するもよし、grep -n hoge
するもよしです。
謎のシリアライズ機能 (new!)
それでとりあえず何が増えたのかというと、ハッシュテーブルやプロパティリストを与えると、それを表現するrosaの文字列に変換する関数が増えました!
CL-USER> (with-input-from-string (in pokemon) (rosa:peruse in)) #<HASH-TABLE :TEST EQL :COUNT 2 {1002956813}> CL-USER> (with-input-from-string (in pokemon) (rosa:indite (rosa:peruse in))) ":diamond-pearl ブイゼル :sun-moon モクロー :sun-moon クワガノン "
それだけです。やったぜ。
いったいどんなユースケースあるのかは謎ですが、おもしろかったので実装しました。
おもしろいなと思ったこと
peruse
とindite
の対が、マセマティカル・モルフォロジーにおける膨張と侵食の関数みたいに、随伴っぽい関係になっているなあ、とふと気づきました。
まとまっていないし、検証も証明もされていないけど、おもしろげであると思ったことをざっと列挙
peruse
とindite
を使うと、二つの領域(文字列、ハッシュテーブル)を行き来できるperuse
すると、文字列はkey-valueなデータに写されるindite
すると、key-valueなデータはrosaの言語に写される
(indite (peruse in))
という関数(モルフォロジの閉包作用素っぽい)を考えると、これは冪等っぽい- どんなテキストファイルでも
peruse
によりrosaの言語の世界に引き込むことができる- あとは
indite
とperuse
で二つの領域をぐるぐるする
- あとは
なんとなく類似を感じた概念等はこちらの本の6章を参照のこと: 『非線形画像・信号処理 (モルフォロジの基礎と応用)』。
おわりに
大学で学んだ抽象的な概念がこのような形で姿を見せるとは、学問とはおもしろいものだなあと思った。
Rosa --- メタデータ付きテキストを表現する言語
Rosa
Rosaは、プレーンテキストにタイトルや作成者などのメタデータを付与するための、メタなマークアップ言語です。また、そのパーサライブラリであり、パーサコマンドの名前でもあります。
ちなみにCommon Lispで実装しました!!!
動機
- ムサシ「何だかんだと聞かれたら」
- コジロウ「聞かせてあげよう我らが名を」
不躾ながらも文章やらなんやらを書くのが趣味なのです。そして書いた文章は、題名や書いた日付や、その他脚注やメモや参考にしたURLなんぞといっしょに同じテキストファイルに残しているわけなんです。そういう付加的な情報はファイルの中に書いておきたい*1。
でも、そんな記法・言語ってあったっけ?
マークアップ言語の中で候補を考えると、XML、Markdown、reStructuredText、JSON、YAMLなどなどいろいろありますが、以下の理由でそれぞれ却下です:
- XML … あの構文はプレーンテキストと相性が悪い
- Markdown … 構文は軽いが、名前を任意に埋め込むのは範疇ではない
- reStructuredText … 構文は軽いが、マークアップ部分がオーバースペック
- JSON … 名前とデータを記述するのにはいいが、プレーンテキストにブラケットはちょっと…
- YAML … JSONよりはいいけど、プレーンテキストにインデントはちょっと…
そもそも、前述の言語は文書構造を表現するものたちであって、付加的な情報を表現するものではないのです。探した限りで、そういう言語は見当たりませんでした。
──そんな言語がないのなら、つくるしかないじゃない! あなたも! わたしも…!!
<2017-03-24追記>
このrosaを、つくっておきながらジャンルがよくわからなかったとき、Masaiさんからメタマークアップ言語では?
と教えていただきました。ありがとうございます!
@sin_clav doc 読んで、たぶんメタマークアップ言語というカテゴリなんだろうなと思ったんですが(markdownの変換自体は別のプログラムに任せれば良い)、はたしてディレクトリとファイル名による分類より優れているのかというとまだ利点が明確でない気がします。
— Asataro.Masai (@guicho271828) 2016年5月5日
で、どんな言語?
というわけでつくったのがrosaでございます。
どんな言語か紹介します。まず、見た目でいうとこんな感じ。
:title あのときの王子くん :author アントワーヌ・ド・サン=テグジュペリ :source-site あおぞら文庫 :source-url http://www.aozora.gr.jp/cards/001265/files/46817_24670.html :body 〈星から出るのに、その子はわたり鳥をつかったんだとおもう。〉 [#改ページ] レオン・ウェルトに 子どものみなさん、ゆるしてください。ぼくはこの本をひとりのおとなのひとにささげます。でもちゃんとしたわけがあるのです。そのおとなのひとは、ぼくのせかいでいちばんの友だちなんです。それにそのひとはなんでもわかるひとで、子どもの本もわかります。しかも、そのひとはいまフランスにいて、さむいなか、おなかをへらしてくるしんでいます。心のささえがいるのです。まだいいわけがほしいのなら、このひともまえは子どもだったので、ぼくはその子どもにこの本をささげることにします。おとなはだれでも、もとは子どもですよね。(みんな、そのことをわすれますけど。)じゃあ、ささげるひとをこう書きなおしましょう。 ...
Rosaのファイルはテキストデータ
とメタデータ
から成ります。テキストデータ
に付けた名前(メタデータ
)を、:
から始まる行で表現します。メタデータの名前
のことをrosaのREADMEの中ではラベル
、ラベル
と呼称しているので、以降もラベル
ということにします。
一行だけのテキストデータと、改行を含むテキストデータで書き方がすこし違います。
インラインラベル
一行のほうは、:
の次から最初のスペースまでがラベル
です(インライン
といいます)。例を示すと、
:hoge-inline Common Lispがすきです
こうです。二つ目以降のスペースはテキストデータの一部になります(ちなみにラベルは[a-z][a-z-]+
の正規表現じゃなければ、ふつうの行だと認識されます)。
ブロックラベル
複数行のほうは、:
からスペースなしの改行までがラベル
になります(ブロック
といいます)。対応するテキストデータの範囲は、次の行から、その次のラベルかファイル終端までです。例示すると、
:hoge-block Commmon Lispが最高に好きです。 Emacsも好きです。 :fuga-inline モクローも好きです。
こう。
コメント&エスケープシーケンス
あと、ブロックラベルには、複数行コメント(行頭の;
はじまり)があったり、:
や;
に対するエスケープシーケンスがあったりします:
:body ; この行は無視されます :; この行はセミコロンから始まります :: この行はコロンから始まります
以上がrosaの構文です。
ちなみに、同名ラベルが複数あったとき、その本体はちゃんと出現順で保持されています。
ライブラリ使用法
Common Lispのライブラリなので、$ ros install t-sin/rosa
で導入でき、REPLで(ql:quickload :rosa)
するとすぐに使用できます。
パースする
パースする関数はperuse
です。Rosaの入力はストリームで渡してください。結果はハッシュテーブルで返ってきます。
(with-input-from-string (in ":label hogehoge") (rosa:peruse in)) ; => #<hash-table ...>
もしすぐに結果が見たければ、peruse-as-plist
を使うとplistで結果が返ってきます。
コマンドライン使用法
だんだんめんどくさくなってきたので簡単に。
機能としては以下の三つのことができます:
- 入力をパースして、ラベルのリストを出力する
- 入力をパースして、指定したラベルのテキストを出力する
- 入力をパースして、入力中の全ラベル - テキストを出力する
それぞれ出力の形式をオプションで選べます。
- プレーンテキスト
- S式 (Common Lispのリスト/plist形式)
- JSON
- YAML
詳細はREADMEを見てください。
ラベル一蘭を出す
$ cat hoge.txt | rosa index ラベルが ズラーっと 出る
指定したラベルの内容を出す
$ cat hoge.txt | rosa pick title -j "hogeタイトル"
全構造を出す
$ cat hoge.txt | rosa pick title -y # YAMLで全構造がずらーっとでる
そのほかのユースケース
テキストファイルのメタデータを表現する以外にも、ラベル - テキストの構造がkey-valueっぽいので、エスケープシーケンスを駆使すれば、デキスト版key-value storeとして使えるような気がしました。非効率だけど。
あと、仕事では一度この使い方をしたことがあるのですが、ウェブAPIのフォームの値をテキストファイルにrosaの形式で書いておけば、それを読み込むプログラムを(Common Lispで)つくりやすかったです。ある種key-value storeとして使ったとも言える。
今後の発展
いまは以下のようなのをぼんやり考えています:
- quicklispに登録しちゃう!?
- パフォーマンス測定
- 巨大ファイルだいじょうぶ?
- 比較対象あれば(だれか教えて!)
- ラベルの文字数制限する?
- テストの実装言語非依存化?
- 別の言語で実装??
- Haskell? Rust?
あと、趣味を改善するプロジェクトとして次は、日本語の文章を表現するためのマークアップ言語hearnを考え中なので、こちらもやらねば。
*1:タイトルやいつ書いたかなどは、ファイル名やパスやファイル更新日時で表現は可能です。でも、気分で変更することもあるので、それらに依存してほしくない。それがファイルの内容に残しておきたい理由です。