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

Lambdaカクテル

ソフトウェア開発者です.玉石混淆です.

言葉に出すこと

日記

上映開始の報を聞いてそのまま予約したチケットに起こされる形で眠い目をこすりながらたどり着いた映画館、の雰囲気はいつもワクワクする。

虐殺器官』。言葉と思考とテロリズムにまつわる哲学的な対話が何度も繰り返されるのは原作となった小説と同じだ。こういう考えさせられるのは好きなので、作者である伊藤計劃氏の早逝が悔やまれる。映画の情景描写が小説を読んで浮かんだ風景とあまり違わなかったのは監督の腕前か原作の描写の卓抜ゆえか。

最近脳が鈍っている。のは、何かを見聞きしたり会話をしても、その内容が頭に残らず、つむじ風のように消えて無くなってしまって本当にそこにあったの?と不安になるような時がよくあるからだ。作中では、〈思考は言葉に規定されるか?〉という一つの問いが発せられる。しかし私は言葉を使っているのか?普段生活していて言葉を使ったと意識した瞬間は何度ある?本当に言葉というものが現れるのは口頭で内省的な会話を行った時くらいのような気がしている。仕事は決まった形式の言語を使えばこなせる。世間話にも考える余地は大して無い。

持ち歩くのが嫌で最低限の金銭しか持ってこなかったおかげでラーメンを食べ損ねた。駅はいつも他人事のような顔をしている。地下鉄に乗った。

内省的な対話ができるのは幸せなことだ。それが喋る楽しみだと思う。どんなところが面白かったの?あれ良かったね。これは好き?どう思う?それはなんで?その問いかけはまっすぐ尖っていて、遠慮がない。親しい間柄の人間にしか許されない行為。世間話には出来ない鋭さ、人間の距離を天秤にかけず無視する危ない楽しみ。聞き上手な人は、その快楽を知っているのかもしれない。

クレジットカードは持っていたから、近場の回転寿司で食べてきた。明るいうちに食べるのは劇場と同じで、なんだか味気の無い諦めっぽい体験だった。外は雨の名残に石畳が黒ずんで光っている。

家で一人になりながらゲームをし時間を裁断していった後圧倒的にかき混ぜられてカクテルパンチになった頭では何も考えられないほど平たくなっていたが、独り言を言ってみた。頭の中の曖昧な部分に血肉が宿り、口から出て行く。それが新鮮で可笑しくてずっと一人で喋っていた。今まで喋らない生活をしていた。内省的な対話をしなかった。それは特権的な行為なのだけれど、人には必要なものだと思う。そこから親密さが生まれる。スマホ越しの文字の投げ合いやゲームの体験では得られない親密さだ。テーブルを囲んで向かい合った時に人は歩み寄ることができる。

今日もまた強くなった。

鴨川を散歩

日記

普段は夕方まで寝ているけれど今日は昼ごろ起きた。天気が良さそうだったのと、シャンプーを切らしていたのを買いたかったので鴨川に散歩に出かけた。

まだ微妙に寒かったが、陽が出ている間はぬくぬくとしていた。親子連れも老夫婦も出歩いて、大勢の人が好天を楽しんでいる。

鴨川はゆったりしている。水面を通った陽がさらさらした水底に光の網を作っていくのが好きだ。流れたり泳いだりする鴨の無為さが好きだ。そこだけ塗りつぶしたように広い、京都の中でもとりわけ広い空が覗くのが好きだ。こんな場所がもっとあればいいのに。

僕は出不精でまだあまり京都を出歩いたことがないものだから、普段よりまぶしい街中で色々なものを見つけた。その足で昼食をとり、薬局に行くまでの道をぶらぶらした。

京都には色々な建物があって、そのどれもが深みを感じさせる。傾き始めた陽を受けて文化の輝きを放っている。 正直なところ、ここまで楽しい散策になるとは思っていなかった。半ば無目的だったのが良かったのかもしれない。普段は大きな荷物を背負って歩くだけで、しなければならないことだけに意識が向いてしまうからだ。そうではなく、ただ鴨川をぶらぶらして立ったり座ったりする中で、人の息遣いだとか、社会の営みに触れられたのが楽しかったし、励みになったようだ。

道を南に下る。

途中でトルコ絨毯の店が小皿やオットマンを軒先に出しているのに目が止まった。赤い看板の下でしばらく立ち止まって躊躇していたけれど、広いガラス張りの向こうに薄暗く見える美しいインテリアに惹かれてなんとなく入ってみた。うちには絨毯もカーペットもない。 細密な文様が織り出された絨毯、モザイクをあしらった天井吊のランプシェード、手描きの絵皿。どこか奥ゆかしさの中にロマンスのある造詣は目と心の両方を愉しませてくれる。あいにく財布を持っていなかったのがかえって幸運で、また来る理由ができた。

gauche/schemeのparser.pegモジュールを使ってSlackの会話をパースした

gauche peg parser scheme

Gaucheのパーサジェネレータ parser.peg の使い方のメモ.

インストール

投稿時点の最新バージョンであるGauche 0.9.5ではparser.pegは標準添付されている.

Gaucheは拡張が豊富なことで人気のscheme処理系である.作者はハワイ在住の日本人エンジニアshiro kawai氏で,日本語・UTF-8に対応しており頼もしい.

$ brew install gauche
$ gosh
gosh> (use parser.peg)
#<undef>
gosh> ^D
$

基本的な流れ

  1. パーサコンビネータを利用してパーサを生成する
  2. peg-parse-string もしくは peg-parse-port を使ってパーサに文字列(ポート)を適用する
  3. パース結果が得られる

パーサの適用

(use parser.peg)
; TODO: implement parser...
(print (peg-parse-string PARSER "string")) ; => parsed result

peg-parse-port を使うと文字列ではなくポートに対してパースができる.

パーサの生成 (パーサコンビネータの使用)

コンビネータの詳細はソースファイルをあたることで参照できる.

以下,よく使うパーサコンビネータを紹介する.サンプルコードでは全て冒頭で(use parser.peg) を宣言しているものとする.

$char

ある文字にマッチし,その文字を返す.

コンビネータにマッチしないときはエラーとなる.他のパーサコンビネータでも同様である.

($char #\!) ; !にマッチする
(peg-parse-string ($char #\!) "!") ; => #\!
(peg-parse-string ($char #\!) "?") ; => *** PARSE-ERROR: expecting #\! at 0, but got #\?

$one-of

文字集合のうちどれか一文字にマッチし,その文字を返す.

($one-of #[a-z]) ; abcdefghijklmnopqrstuvwxyz のどれかにマッチする
(peg-parse-string ($one-of #[a-z]) "g") ; => #\g

$many

コンビネータの繰り返しにマッチし,リストを返す.最小文字数と最大文字数を指定できる.

最大文字数を超過しても,パーサはエラーを返さないことに注意.パーサは最大文字数に到達したことで満足し,文字列を読み取るのを止める.正規表現と同じである. 確実に最大文字数を守らせたいならば,コンビネータ eof を組み合わせるべきである.

($many ($one-of #[a-z])) ; a-zの繰り返しにマッチする
(peg-parse-string ($many ($one-of #[a-z])) "hoge") ; => (#\h #\o #\g #\e)
;; 最低5文字を要求する
(peg-parse-string ($many ($one-of #[a-z]) 5) "hoge") ; => *** PARSE-ERROR: expecting #[a-z] at 4, but got #<eof>
;; 5〜7文字を要求する
(peg-parse-string ($many ($one-of #[a-z]) 5 7) "hogera") ; => (#\h #\o #\g #\e #\r #\a)
;; 文字数を超過するとコンビネータは満足して探索をやめる.エラーにはならない
(peg-parse-string ($many ($one-of #[a-z]) 5 7) "hogerarara") ; => (#\h #\o #\g #\e #\r #\a #\r)

$seq

コンビネータが指示した順に並んでいるときにマッチする.順の最後のコンビネータの返り値を返す.

; $count: ちょうどその回数にマッチする
; digit: デフォルトで使用できるコンビネータ(文字集合ではないことに注意).
;        任意の数字にマッチする.
;        newline, space, spaces, alnumなどの仲間もある
; $c: $charのエイリアス
($seq ($count digit 3) ($c #\-) ($count digit 4)) ; 郵便番号にマッチさせる
(peg-parse-string ($seq ($count digit 3) ($c #\-) ($count digit 4)) "123-4567") ; => (#\4 #\5 #\6 #\7)

$do

$return と組合せて使う.マッチしたコンビネータから値を取り出し,加工して取り出す.

コンビネータを名前に束縛する際,コンビネータであることが分かりやすいように接頭辞%を付している.

(define %head ($count digit 3))
(define %tail ($count digit 4))
(define %postal
  ($do
    [h %head] ; %headが返す値がhに束縛される
    [dash ($c #\-)]
    [t %tail] ; %tailが返す値がtに束縛される
    ($return (list (list->string h) #"~dash" (list->string t))))) ; h, dash, tを利用して値を作り出す.$returnした値が$doが返す値になる
(peg-parse-string %postal "123-4567") ; => ("123" "-" "4567")

$lift

$do のモナディックなシンタックスシュガー.

; ($lift f parser) == ($do [x parser] ($return (f x)))
(define %head ($lift list->string ($count digit 3))) ; 3文字の数字にマッチし,文字のリストを list->stringに渡し,得られた値を返す
(define %dash ($lift ($ list->string $ list $) ($c #\-))) ; $はパーサとは関係ないマクロ[1]
(define %tail ($lift list->string ($count digit 4)))
(define %postal
  ($lift list %head %dash %tail)) ; %head, %dash, %tail それぞれの値が3引数としてlistに渡され,その結果が返り値となる
(define %postal-naive
  ($do [h %head] [d %dash] [t %tail] ($return (list h d t)))) ; 上掲を$doで書き直したもの

(peg-parse-string %postal "123-4567") ; => ("123" "-" "4567")
(peg-parse-string %postal-naive "123-4567") ; => ("123" "-" "4567")

$sep-by

デリミタとなるコンビネータで区切られた文字列にマッチし,デリミタを除いたリストを返す.

; $optionalは省略可能であることを示すコンビネータ.
(define %comma ($seq ($c #\,) ($optional space)))
(define %number ($lift ($ string->number $ list->string $) ($many digit 1)))
(define %comma-separated ($sep-by %number %comma))
(peg-parse-string %comma-separated "1, 2,3,4, 5, 6") ; => (1 2 3 4 5 6)

$alternate

おおむね$sep-byと同じ挙動だが,マッチしなかった場合の挙動が異なる.ちょっとこれは説明しづらい. マッチしなかったとき最後のデリミタの直前からバックトラック*1を行うので,デリミタが複数の意味で使われうるシチュエーションに適している. また,デリミタを捨てない.

(define %comma ($c #\,))
(define %period ($c #\.))
(define %word ($many upper 1))
(define %trailing-phrase ($do [us %word] [_ %comma] ($return (list->string us))))
(define %last-phrase ($do [_ space] [us %word] [_ %period] ($return (list->string us))))
(define %enumeration ($lift cons ($alternate %trailing-phrase space) %last-phrase))
(peg-parse-string %enumeration "VENI, VIDI, VICI.") ; => (("VENI" #\space "VIDI") . "VICI")

$between

2つのコンビネータに挟まれたものにマッチし,挟まれていた値を返す.

(define %number ($lift ($ string->number $ list->string $) ($many digit 1)))
(define %parenthesized-number ($between ($c #\() %number ($c #\))))
(peg-parse-string %parenthesized-number "(128)") ; => 128

$or

自明なので省略.他にも様々なコンビネータが用意されているので,コードを見て遊んでみてほしい.

試作 - Slack会話のパース

学んだことを形にしてみるために,parser.pegを使ってSlackのログパーサーを作ってみた.50行ほど.

ログはクライアントからコピペしてきた.ツールがうまく動かずに苦しんでいる様子が克明に記録されている.

github.com

(use parser.slack)
(print (slack-parse "windymelt [5:31 PM] 
ぽへー

[5:31]  
ちょっちQKしよ

windymelt [5:40 PM] 
ぽえ〜〜〜

[5:40]  
ぽよよよよ

[5:40]  
びー

windymelt [7:14 PM] 
ぽよ〜〜〜〜

[7:14]  
ぽぽぽぽぽ
"))
((windymelt
  (((5 31 PM) ぽへー)
   ((5 31 #f) ちょっちQKしよ)))
 (windymelt
  (((5 40 PM) ぽえ〜〜〜)
   ((5 40 #f) ぽよよよよ)
   ((5 40 #f) びー)))
 (windymelt
  (((7 14 PM) ぽよ〜〜〜〜)
   ((7 14 #f) ぽぽぽぽぽ))))

簡単にパーサが作れたね!util.matchと組み合わせたら加工もしやすそう.ここからの発展形として,HTMLに変換して出力するなどが考えられる.gauche.parseoptモジュールを使ってコマンドラインを処理すれば,手製のコマンドをパパッと書くことだってできそうだ.

参考文献

blog.shin1x1.com

*1:「後続のパターンがマッチしない場合に一つ前のパターンに戻って、別のマッチ方法を試行するのをバックトラック(backtracking)と呼びます」 パフォーマンスを意識して正規表現を書く - Shin x Blog

最近買った本の雑な紹介

ある程度読んだ本もあれば,さっきポチったのもあります.

『面倒だから、しよう』

いいことが書いてある本.自分の自由な意思を発揮して美しく生きるということが強調されている.著者はカトリック方面の人.読みきった.同著者の『置かれた場所で咲きなさい』のほうが有名だと思う.

面倒だから、しよう

面倒だから、しよう

利己的な遺伝子

うわっ角が鋭くて固い.ソフトカバーとは思えない,『オブジェクト指向入門』以来の(こちらはそれほど大きいわけではないが)デカさ.ヒトの進化の話.まだ少ししか読めていない. 威圧感にちょっと後悔しつつある.

利己的な遺伝子 <増補新装版>

利己的な遺伝子 <増補新装版>

ピクサー流 創造するちから』

アニメーションスタジオとして有名なピクサーを作ったおっさんがやったこともない管理職として苦労する話.ジョブズが出てくるとこらへんまで読んだ.

ジョブズが他人を"傲慢"呼ばわりするくだりが面白い.傲慢はプログラマの美徳だもんね.

ピクサー流 創造するちから―小さな可能性から、大きな価値を生み出す方法

ピクサー流 創造するちから―小さな可能性から、大きな価値を生み出す方法

『嘔吐』

フランスの哲学者サルトルが書いた小説形式の哲学書ということになっているらしい.男が始終ストレスフルで,あらゆる物が鬱陶しくなってずっと脳内でキレまくる話.四分の一くらい読んだ.あらゆる物が鬱陶しくなったりすることがあるのでまあまあ共感できる.まだ吐いてないし,これから先吐くかはわからない.

嘔吐 新訳

嘔吐 新訳

女工哀史

明治大正にかけてのクソブラック紡績工場で働かされていた人がその境遇を記録したもの.刊行後長くないうちに著者は死亡している.病死したり過労死したり,日本の労働者は大変だなあ(棒読み) 歴史は繰り返すって言うからね・・・

女工哀史 (岩波文庫 青 135-1)

女工哀史 (岩波文庫 青 135-1)

日記

コーダーハイ

定時前になるとやたら頭が働くのはなぜだろう。今日の仕事の半分近くが定時前の1時間で行われたような感覚だ。それだけ日中は漫然としているということだろうか。それとも邪魔が入らず集中できるからだろうか。最高の環境を作っていきたい。

プログラミングに没頭しているとき、猛烈に頭が動いてアドレナリンが脳内に浸透し、神経が研ぎ澄まされ、そのまま死ぬのではないかと思えるほどハイになる時すらあって、パンツァーハイならぬコーダーハイだなぁ。ただ毎度疲れてしまうから愛憎こもごも。できれば穏やかでいたい。

タイマー

そういえば最近とても寒くて、朝から暖房を回していないとベッドから出られない。部屋全体を暖めるためのサーキュレーターにはタイマーが付いていないので、起きても部屋は天井近くを除いて冷たいままだ。タイマーを作りたい。

日記

この土日は比較的落ち着いた二日間にできた。とはいえ、ただパソコンをあまり開かずに読書に没頭する時間を、二時間ばかり持てたというだけのことだが。

読書をした

読書をしている間は心が落ち着く。最近は本を捉えるだけの集中力も持続できるようになった。良いことだと思う。できることなら、ずっとその集中力が続いて、本の中に入り、そのままその世界の端まで駆け抜けて行きたい。でもそうはならないので、だんだんと今いる部屋に意識が連れ戻される間隔が短くなり、ついに読めなくなってしまう。そのうち、本を読めない自分に苛立ってきてしまう。なんだか自分を責めすぎだと思う。

一人で暮らしていると、誰かと時間を潰せなくなる。適当に過ごす時間から大義が奪われる。何かを為さなければならない時間になってしまう。その威圧に飲み込まれがちだ。一人暮らしはそんなに良いものでもない。

アウトプット事情

最近はアウトプットをプライベートな日記にもあまりしなかった。頭の中が散らかっていて、その気になれなかった。特に重大な何かが身に降りかかったわけでもないのに、ためらいがちに心がそわそわするのを感じる。大切な何かを忘れていて、いずれそれが暴露されて苦しむのではないかという不安感が、霧のように視界を遮り、足元を惑わせる。

アウトプットすることで頭の中が片付くならそれがいいが、いざ頭の中の断片を拾い出すと、普段頭の中でもやもやしている観念が、意識の海面から姿を消してしまう。本来ならばここで踏ん張って釣り上げる努力をすべきなのかもしれない。だがそれに対する本能的な抵抗、忘れていた方が良かったかもしれないものを思い出させまいとする抵抗が髪の毛を引っ張って、意志をかき乱してしまう。

まあそれでも明日は来る。それでやっていくしかない。誇りを持ってやることをやるのが一番無害だ。

愚痴を言う

愚痴を言うのが下手だ。自分でも何を言っているのかわからなかったり、もっとひどいと何を言えば良いか分からなくて途方にくれることもある。それは単に悩んでいるだけで、原因も何もないのかもしれない。その境界線が分かればいいが、たいてい手遅れになって悩んでしまっている。悩みから目をそらすだけの心の広さがないから、笑顔でなだめていくしかない。

明日はもっといい一日になる。笑顔でいこう。

CLIでOSSなパスワードマネージャ「pass」とNFC Ringとで今年こそパスワードを倒す

パスワード oss nfc ring

NFC Ringを買った.これはNFCタグを伴った指輪で,プログラマはタグのユーザ領域を好きに使うことができる.めっちゃかっこいい.

f:id:Windymelt:20170117011542j:plain

(画像は Horizon – NFC Ringより引用)

nfcring.com

僕はこの活用法として,NFC Ringを鍵としたスマートなパスワード管理という構想を実現させようと思った.

しかし自前でパスワードマネージャを書くのは練習になるとはいえリスキーだと思い,OSSで何か良いものはないかと探してみたら面白いツールを見つけた.pass というシンプルな名前のツール.検索しにくそうだ.

www.passwordstore.org

これは,UNIX哲学に則りgitとPGPでパスワードを管理するツールのようだ.gitもPGPも大好きだ.これを使わない手はない.NFC Ringと連動させれば,CUI特有の面倒も軽減できるだろう.

アーキテクチャ

アーキテクチャは以下の通り.

  • NFC Ring
    • PGP鍵を復号するパスフレーズを供給する.
    • 紛失した場合,PGP鍵を即座に無効化する必要がある.ここは難しい.
    • Pythonでデータを読み取れる(実質1KiBのフラッシュメモリなのだから)ので,連携は難しくないはず.
    • 本物のNFC Ringであることを保証する電子署名機能が付属している高めのモデルにした.
  • Pass
    • パスワード管理を担当.
    • パスワードDBはGitHubかBitbucketなどに,プライベートレポジトリとして保管する.
  • Da Vinci 32U
  • ブラウザ拡張
    • 見ているサイト,フォーカスが当たっている要素を認識する.
    • 既にchrome向けの拡張が存在するので,これに手を加えることもできる.

これらの協調によって,望みのサイトの画面でNFC Ringをタッチすれば,自動的にパスワードを入力できるようになるはずだ.

やっていくぞ

passを見付けたのが深夜だったので実装はまた次に.ちなみに届いたNFCRingだが,サイズを間違えてスカスカだったので,交換しようという気持ちになっている.楽しみにしていたのにめっちゃつらいし,凹んでいる.

参考文献

d.hatena.ne.jp

パスワードと戦っている様子

windymelt.hatenablog.com

windymelt.hatenablog.com

windymelt.hatenablog.com