みどりねこ日記

よくわからないけど、頑張りますよ。

祖父が他界した

祖父が他界した。

祖父は生前仏教を信仰していて、修行したらしく戒名ももらっていた。

ちなみに言うと僕は神なんか信じてない。

それで、ここのところ葬式とかで忙しかったのだけれど、 いろいろと腹が立つことがあったのでぶちまける。

まず祖父の行っていたお寺の住職が生臭坊主で、

妻帯者でありながら(しかもお坊さんだろ!!!)浮気してた。

しかも毎週1度ふらっと祖母の家に現れては5000円せびっていく。

そりゃ立派な僧で祈っていただきたいと思える人なら話は別だが、1ヶ月に2万円も要求するの?収入もあまりない老人から?おまえが?

その金で浮気相手に貢ぐのかと思うと反吐が出る。

白々しくも棺に入った祖父の額に手を当てて

「もう大丈夫です、頑張りましたね」

とか言ってたし。死ね。爺さんに触るな、穢れる。

仏教の一連の葬儀は金儲けのためのシステムに見えてならない。

祖父が亡くなったとどこから聞いたのか知らないがいろんな業者がやってきて祖母に金を要求する。

しかも毎週これこれを買ってこれを供えてださい、こちらで買えますよ、これも必要です、…。

それで祖母の気が晴れるなら、と思うが、この業者どもの白々しい「お悔やみ」を嫌悪する。

死ね。

僕は神なんか信じてない。

神を信じろって言ってくる人と付き合いたいとは思わないだろう、これからずっと。

パーサの連接とか

前回までに出てきた基本的なパーサをくっつけることで複雑なパーサが書けるわけですが、 今回はそのような連接とかを手助けしてくれるパーサコンビネータを紹介?します。

Kern のパーサコンビネータはシーケンス化、反復、選択、それと括弧の対応とかの面倒を見てくれるみたいです。

例のごとく kern をロード。

(use 'blancas.kern.core)

skip-ws は入力のはじめにあるすべての空白をスキップ。

doc.core> (run (skip-ws letter) "\t \n x")
\x
nil

<|> はあたえられたパーサを成功するまで試す。すべてのパーサが失敗するか、入力を消費するパーサが失敗すると全体として失敗する。

doc.core> (run (<|> digit letter) "x")
\x
nil
doc.core> (run (<|> digit letter) "9")
\9
nil
doc.core> (run (<|> digit letter tab) "?")
line 1 column 1
unexpected \?
expecting digit, letter or tab
nil

で、 >> は1つ以上のパーサを適用する。最後のパーサの結果だけを返す。

doc.core> (run (>> digit digit letter) "91x")
\x
nil

<< は1つ以上のパーサを適用する。最初のパーサの結果だけを返す。

doc.core> (run (<< upper (sym* \-) digit digit) "F-16")
\F
nil

<$> は与えられたパーサを入力に適用して、そのあとパースした結果に対して与えられた関数を適用、その結果を返す。

doc.core> (run (<$> #(* % %) dec-num) "12")
144
nil

<*> は2つ以上のパーサを適用して、それらの結果をベクタにして返す。

doc.core> (run (<*> dec-num tab oct-num tab hex-num) "737\t747\tA340")
[737 \tab 487 \tab 41792]
nil

<:> はバックトラックするパーサらしい。もし失敗しても消費した入力は回復。

doc.core> (:input (parse (<:> float-num) "5005.a"))
(\5 \0 \0 \5 \. \a)

many は入力に対しパーサを0回以上、失敗するまで適用。many1 は1回以上で、最低1回生功しないと失敗。

doc.core> (run (many letter) "123")
[]
nil
doc.core> (run (many letter) "xyz")
[\x \y \z]
nil
doc.core> (run (many1 letter) "xyz")
[\x \y \z]
nil
doc.core> (run (many1 letter) "123")
line 1 column 1
unexpected \1
expecting letter
nil

optional はパーサが成功するか消費を行わかなった場合に全体として成功する。

doc.core> (run (<+> (optional (sym* \-)) dec-num) "-45")
"-45"
nil
doc.core> (run (<+> (optional (sym* \-)) dec-num) "45") 
"45"
nil
doc.core> (run (<+> (optional float-num) letter) "45.A")
line 1 column 4
unexpected \A
expecting digit
nil

option は与えられたパーサを適用する。もし入力を消費せずに失敗したら、与えられた値を結果として返すっぽい。

doc.core> (run (option 3.1416 float-num) "foo")
3.1416
nil

skip は1つ以上のパーサを取ってそれらの結果をすべて飛ばす。結果として nil を返す。

doc.core> (run (skip letter digit letter digit) "A5E8") 
nil
nil

skip-many はパーサを0回以上適用し結果を飛ばす。nil を返す。skip-many は1回以上。

doc.core> (run (skip-many letter) "xyz")
nil
nil
doc.core> (run (skip-many1 letter) "xyz") 
nil
nil
doc.core> (run (skip-many1 letter) "123")
line 1 column 1
unexpected \1
expecting letter
nil

sep-by は与えられたパーサによって分けたものに対して別のパーサを0回以上適用する。sep-by1 は1回以上。

doc.core> (run (sep-by (sym* \&) (many1 letter)) "a&bb&ccc&ddd")
[[\a] [\b \b] [\c \c \c] [\d \d \d]]
nil

end-by は与えられたパーサによって別れる/終わるものに対して別のパーサを0回以上適用する。end-by1 は1回以上。

doc.core> (run (end-by (sym* \&) (many1 letter)) "a&bb&ccc&")
[[\a] [\b \b] [\c \c \c]]
nil

between は1,2つ目のパーサの間のちに対して3つ目のパーサを適用する。

doc.core> (run (between (sym \() (sym \)) dec-num) "(1984)")
1984
nil

<+> はひとつ以上のパーサをとる。で、結果を潰してくっつけて、文字列にする。

doc.core> (run (<+> letter (many alpha-num)) "a177")
"a177"
nil

数字のパース

kern にはいくつか数値のパーサが用意されてて、これらは結果として文字列ではなく適切な数値型を返します。これらのパーサは名前空間 lexer 内のそれらに比べてサポートする数値型は少ないし、空白とかコメントとかもスキップしません。つまるところ、大きなパーサの低レベルの部分で使うべき関数みたいですね。

使用にあたって Kern の名前空間 core をロードします。

(use 'blancas.kern.core)

value はパーサを走らせてそのパース結果を返す関数です。引数としてパーサと文字列を受け取って、オプションとして文字列が何であるか(例えばファイルネームだとか)を示すことができます。

dec-num は十進数の正数をパースして結果として long 型を返します。

doc.core> (value dec-num "8086")
8086

oct-num は8進数の正数をパースして結果として long 型を返します。

doc.core> (value hex-num "747")
487

hex-num は16進数をパースして結果として long 型を返します。 0x が先頭につくものは許されません。

doc.core> (value hex-num "FEED")
65261

float-num は浮動小数点数をパースして結果として double 型を返します。指数表現はサポートされていません。 lexer 内の float-lit ではサポートされてます。

doc.core> (value float-num "3.1415927")
3.1415927

Kern のプリミティブパーサ

Kern にもプリミティブなパーサがあって、これらを組み合わせていくことで大きなパーサを作るというのが関数型らしいパーサの作り方なわけですが。 それらをちょっと見ていきます。 Kern けっこうかわいいわあ。

(use 'blancas.kern.core)

return は常に成功し、与えられた値を返す。

doc.core> (run (return "foo") "xyz")
"foo"
nil

fail は与えられたエラーメッセージとともに失敗する。

doc.core> (:ok (parse (fail "foo") "xyz"))
false
doc.core> (run (fail "this is bad") "xyz")
line 1 column 1
this is bad
nil

satisfy は与えられた述語を入力の最初の文字に適用し、それによって成功か失敗かが決まる。

doc.core> (run (satisfy #(= \x %)) "xyz")
\x
nil

any-char は入力された文字を返す。

doc.core> (run any-char "x")
\x
nil

letter は大文字小文字のどちらも成功する。

doc.core> (run letter "z")
\z
nil

lower, upper はそのまんま。

doc.core> (run lower "a")
\a
nil
doc.core> (run upper "M")
\M
nil

white-space は空白文字を受け付ける。

doc.core> (run white-space "\t")
\tab
nil

space はスペースだけ。 tab もまあそんなかんじ。

doc.core> (run space " ")
\space
nil

digit は \0 から \9 までの数字を受け付ける。 hex-digit はそれに加えて \A から \F まで。 oct-digit は \0 から \7 まで。

doc.core> (run digit "9")
\9
nil

alpha-num は英数字。

doc.core> (run (many alpha-num) "9A")
[\9 \A]
nil

sym* は特定の文字だけ。 sym- は大文字小文字関係なく。ただし結果として得る文字は sym- に渡された文字。

doc.core> (run (sym* \x) "x")
\x
nil

token* は Haskell でいう string パーサ。複数のシーケンスが渡された場合、どれかが成功するまで試され続ける。 token- は大文字小文字関係なく。

doc.core> (run (token* "foo" "bar" "baz") "bazaar")
"baz"
nil

word は token と同じようなものだけれど、許可しない終端を設定できる。 word- は大文字小文字関係なく。

doc.core> (run (word* (one-of* "|-/") "foobar"))
"foobar"
nil
doc.core> (run (word* (one-of* "|-/") "football" "foobar") "foobar*")
"foobar"
nil
doc.core> (run (word* (one-of* "|-/") "foobar") "foobar/")
line 1 column 8
unexpected /
expecting end of foobar
nil

one-of は与えられた文字列のどれかの文字であれば受け付ける。 none-of はその逆。

doc.core> (run (one-of* "xyz") "zap")
\z
nil

new-line* は \n を受け付ける。 eof はもし入力が空なら成功する。

field* は与えられた文字列で区切られる文字列をパースする。

doc.core> (run (field ",;") "California,")
"California"
nil

split-on は空白か与えられた文字列で区切られる文字列を分割する。

doc.core> (run (split-on ",./") "Now, is the time")
["Now" "is the time"]
nil

split は空白で区切られたテキストを分割する。

doc.core> (run split "Now is the time")
["Now" "is" "the" "time"]

Clojure の パーサコンビネータライブラリ Kern

Clojure でパースするとき、みんなどうしてるんだろう。 Parsec のようなものがあればいいのに〜、と思って探してみたところ、この Kern が一番よさげだった。

特徴

  • 状態モナドベースのコンビネータ
  • C, Java, Haskell, Shell の構文をサポート
  • パースと式の評価をサポート
  • 正確で詳しいエラーメッセージ
  • エラーメッセージは簡単に多言語化可能
  • パーサの内部状態にクライアントコードからアクセス可能
  • サンプルあり

セットアップ

leiningen がインストールされているなら、 project.clj の :dependencies に

[org.blancas/kern "0.6.1"]

で、コード中に

(use 'blancas.kern.core)

Haskell の Parsec っぽい

HaskellのParsecですねという感じ。というか記号とかもそのまんま。 ただちょいちょい違うところがあるかなあという印象。

例えば数字のパース。

doc.core> (run digit "123")
\1
nil
doc.core> (run (many digit) "123")
[\1 \2 \3]
nil

run はパース結果を印字する。パースしてない残りの入力はそのまま。パーサの状態は run* で見れる。

doc.core> (run* digit "123")
{:input (\2 \3),
 :pos {:src "", :line 1, :col 2},
 :value \1,
 :ok true,
 :empty false,
 :user nil,
 :error nil}
nil

文字列以外にも入力としてファイルとかも受け付ける。 runf は パーサとファイル名、文字コードを受け取ってパースする。

コンビネータ <*> は与えられたパーサを順に実行し結果をベクタにして返す。

doc.core> (run (<*> letter letter digit) "os8")
[\o \s \8]
nil

parse は run みたいな動作をするけれどパーサの状態を返すという点で異なる。 :ok フィールドをチェックすればパースに成功したかどうか分かる。 :value セレクタを用いればパーサの結果が得られる。

doc.core> (let [st (parse (token* "abc") "abc")]
        (when (:ok st) (str "got " (:value st))))
"got abc"

Clojure on Mac OS X Lion : heroku + compojure + hiccup

絶賛テスト前でつらいので現実逃避してClojureで遊んでみた。

開発は Emacs + nrepl + clojure-mode + leingingen です。

https://github.com/technomancy/clojure-mode

https://github.com/kingtim/nrepl.el

https://github.com/technomancy/leiningen

このへんを見てもらえばだいたい準備できるかと。

gem install heroku

でherokuコマンドを用意。 今回は postgresql も使ったので

brew install postgresql
export PORT=8080
initdb pg

ここでメモリ足りないみたいなエラー吐かれたので

sudo sysctl -w kern.sysv.shmall=65536
sudo sysctl -w kern.sysv.shmmax=16777216
initdb pg
postgres -D pg&
createdb script
export DATABASE_URL=postgres://localhost:5432/script
heroku create --stack cedar

適当になにか書く。

git init
git add .
git commit -m "initial commit"
git push heroku master

うまくherokuにpushできたら、

heroku open

で確認できます。

もしうまくpushできないのなら、コンパイルがきちんと通るか試してみてください。あと、使うライブラリによってはなぜかApplication Error吐かれます。hiccup.page-helpersはだめでした。

heroku側でpostgresql使おうと思ったら、

heroku addons:add shared-database

でエラー。 どうやらheroku-postgresqlを使うべきらしい。 それにあわせてDBのパスも変える。

heroku addons:add heroku-postgresql
export HEROKU_POSTGRESQL_CYAN_URL=postgres://localhost:5432/script

準備できたのでhiccupでHTMLを生成してもらって、compojureでルーティングしてもらう。

さすがLispというべきか、こういうデータ構造は書きやすい。

(defn page-template [title body]
  (html
   [:html
    [:head
     [:meta {:charset "utf-8"}]
     [:title title]
     [:script {:src "http://code.jquery.com/jquery-latest.js"}]
     [:script {:src "/js/bootstrap.min.js"}]
     [:script {:src "/google-code-prettify/prettify.js"}]
     [:link {:rel "stylesheet" :href "/google-code/prettify/prettify.css"}]
     [:link {:rel "stylesheet" :href "/css/bootstrap.css"}]
     [:link {:rel "icon" :href "/favicon.ico"}]]
    [:body {:onload "prettyPrint()"}
     [:div {:id "header" :class "page-header container"}
      [:h1
       [:a {:href "/"} "~"] "/" title]]
     [:div {:class "row"}
      [:div {:class "span1"}]
      [:div {:id "menu" :class "container span2"} (menu)]
      [:div {:class "span1"}]
      [:div {:id "content" :class "container span12"} body]]
     [:footer {:style "text-align:center"}
      "generated by compojure and hiccup."]]]))

(defn page-not-found []
  (page-template
   "404"
   [:div {:id "not-found"}
    "404 page not found"]))

動物がものになるとき

昨夜遅くに帰宅してお酒をあおったあとそのまま寝てしまったようで、起きると11時になっていた。 今日は講義が休みだったので大したことはない。さて、同人誌の記事を書かねば。

自宅で同人誌が書けないことは自明なのでとりあえず駅前の美味しいワッフル屋にでも行ってみよう。 久しぶりだし髪も切って。

そう思って外に出ると雪が降っていた。 広島で暮らしている頃はホワイトクリスマスにあこがれていたけれど、長野に来てからはとにかく降らないことを祈って毎日を過ごしている。 しかも今日は-5℃とかなんの冗談なんでしょうかね。 北海道ではよくあることだそうですが…

美容院のお姉さんと世間話していると、今までに飼ったペットについて話が広がった。 今でもミミズだって触れるなどとのたまう美容院のお姉さん。 僕も昔はミミズとかカタツムリとかカメみたいなアレな動物飼っていたが、いまではナメクジだって触りたくないのに!

余談だけれど、ミミズを与えるとカメが喜ぶので、小学生のころいつも庭を掘り返して探していた。ある時、 ミミズを繁殖させれば簡単だと思いついて水槽に泥をたくさん入れてミミズファームなるものを作った。 彼らが水の中で活発に活動することを知っていたので嬉しがっているんだと思い水をジャブジャブ入れた。 私の可愛い家畜たちは一夜にして肥大化し大成功に思えたが実際にはミミズファームは全滅していた。溺死である。 ミミズは水の中で呼吸できないので、雨の日に地表に出てくるということをその時知った。アーメン。

そんな話をして、僕の髪がさっぱりしてきたころ、接待気味になってきた生返事お姉さんが 「次は何を飼われるんですかー?」 と聞いてきた。

その質問で、ふと今年の夏に食事をした高校の同級生の家族を思い出した。

その家族は昨年から犬を飼い始めたらしく、珍しい犬種らしい。 うちも犬を飼っているので自然と犬の話になる。

犬を飼い始めた経緯について聞くと、どうやらインターネットショッピングしたらしい。 犬種は忘れたが確かに珍しいらしく、その犬種の特定毛色の犬が飼いたかったそうで、 インターネットでその毛色の犬をたまたま見つけたらしく電話越しで「注文」したそうだ。 この時点で僕はかなり胸糞悪い気分だったのだが。

そして届いてみれば、その犬は表記されていた毛色とは全く違う色だったそうで、 要するにペット詐欺に引っかかったのだ。 「返品」をお願いしたが受け付けてもらえず、「仕方なく」飼うことになったという。

そしてあろうことか、その毛色の犬があきらめられず、別の業者に再び電話越しで「注文」。 今度はその毛色の犬が届いたとおもいきや、体調が悪い。 しばらくしても治らないので獣医に連れていくと皮膚病だという。 その原因は染料。

犬は客の要望に合わせて業者に色を塗られて売られていたのだ。

染料を落とすと全く違う色の犬になり、家族は「がっかりした」そうだ。

はっきり言って僕はこの家族と食事することが苦痛でならなかった。 この話を聞いた時点で席を立ちたかったが、そもそも同級生が僕の家族に会いたいと言い出して、 僕がセットアップした会だったのでそういうわけにもいかない。

そのあとしばらくそんな話を聞き続けた。

「うちの犬たちに会いに来て欲しい」なんて言っていたが、 もう一生その家族と会うことはないだろう。 会いたくない。

その家族の言い分もわからなくはない。 高いお金を払って思い入れのあるものを買ったつもりが、ぜんぜん違うものだったら返品もやむなしだろう。

しかし、犬は動物なのだ。 動物はものなんかじゃない。

なにがあっても最後まで面倒をみるという覚悟がない人が動物を飼おうとしないでほしい。

というのが僕が率直に思った意見だ。 しかしふと自分を見返すと、僕は確かに犬やカメを大事に飼っているつもりだけど、 では死なせてしまったミミズや幼い頃に飼おうとして共食いさせてしまったバッタはどうだっただろうか。

動物を飼うと自分のエゴや人のエゴが見え隠れするようになる。

そもそも動物は飼われるべきなのか?動物は商品として、ものとして扱うべきなのか?

僕にはわからない。 ただ、せめて我が家の愛犬を大事に育てようと決めた。

さて、現実逃避をやめて原稿を書こう。