年を越せ

何がそんなにめでたいというんだ?無事に年越しを迎えられるのがめでたいのなら他の瞬間だって同じだ、毎分毎秒祝うべきじゃないのか?

人生の本質はたぶん忘却にあって、無事のありがたみを年越し一点に押し込めることによって他の時間はありがたくなく過ごすことができます。でも別に無事でいることだって本当の人生を思い出したらそんなにありがたいことじゃないので年を越した瞬間だったとて。それが理由で僕は年越しをそんなに珍重しないのではないだろうかとふと思う。

(年越しをそんなに珍重しないというのは完全に嘘で、毎年ジャンプしたり何だったりを一応していた。高校までは。大学に入って一人で過ごすようになってからはもはやどうでもよくなり、結局は横に人間がいたりいなかったりするのが理由なのか?でも僕の親はもう随分前から年を食っていて、1/1へとかわる記念すべき24:00はいつだって寝ていた。かつては叩き起こしたりしていたけど普通にかわいそうだったのでやめました、親は大事にしましょう。)

よいお年をって言ってるのも忘却の一種でしょう、よいお年をって今年一年だけでいいわけないだろ、良い人生をって言えよ。まあ人生が良かったところで何もないんですが……。これも一年単位なんですよ、来年のことは来年の正月に。セクションで人生を埋め尽くすことができるんですよ、知っていましたか?俺は知っていた。さっきようやく気がついたんだ。

人間が一年単位で忘却に押し込めることは単に利便性が理由だと思うんだけど、何やら伝統とか道徳を帯びるのは気に食わないですよね。僕はそうです、かなり気に入らない!こう、正月に初詣に行くと、『あの人は「ちゃんと」正月を祝う人だ』みたいな評価を得られるのおかしくない?俺は必ず道で見かけた蛇を蹴り殺している*1んだけど、これを話したところでこのエピソードに「ちゃんと」はつかない。なんでだよ。蛇が干支だからか?「ちゃんと」=「許容的な」で表層を、膨大な非許容的振る舞いを本質に社会を構成しているくせによく言いますね、あるいはそうだからそう言うのかもしれないけれど。死骸と歴史を中心核に、初詣を一番外側に持つ地球様の球体の上でのうのうと営む暮らしはいかがですか?暮らし自体はいいですよ、人生は最悪ですが、としか言えんなこんなもん。

本当は一年以外といわず全部忘れたいので酒を飲みたいです。いつか落ち着いたらいきましょうみなさん。蛇と蛇以外の大勢がもう死んでしまったか、あるいは僕らが殺しました。彼らはもう生きていられなかったけど、我々はせめて次の巳年くらいまでは生きていたいですね。そういえば四半期って言葉があるなあ、なんでもまずは四等分を目指すのが筋が良いのかもしれないとふと思った。そうなると言う言葉が一意になってしまう!まあ子年の最後の言葉としてはふさわしいのか*2

良いお年を。

(おわりです)

*1:0/0

*2:一意だけにって言ったら斜にタコ殴りにされそうだけどまっすぐ生きていきたいので言います、一意だけに。

書くことがない

 文章を書くのが好きな割には全然書いていない。
 理由としてまず忙しいというのがあるのだが、しかし空き時間をスマブラなりyoutubeなりに突っ込んでいることを考えるとこれは真の理由ではなくて、実際のところ僕は忙しいと感じているときに文章を書いてはいけないと思っている。こっちが真因だ。
 僕の中での知覚として、文章を書くというのは頭脳を消費する行動であって、そうすると課題なり研究なりのやるべきことが残っているときに文章を書いてはいけないという枷がかかっている。同様に趣味でプログラムを書くとかもそうで、そのせいで全然プログラムを書けていない。advent calendarだって一つも参加できなかった。その割にスマブラはうまくなっていくし、youtubeで見た音MADの集積で僕の脳は満たされていく。本当にこれで良いのか自分でも全くわからない。

 でも今日はなんかその知覚がバグったので久々に文章を書こうと思う。さらっと5000文字くらい書いたらやめにしよう。あと僕は文章を書くときに直前に読んでいた文章の文体に極めて(本当に極めて)強い影響を受けるのだが、今日は江國香織なのでマジで珍しい感じになると思う。

 書くということだけ決めて書き始めたので微塵もテーマがないので近況でも書こうので。多いね?大学院に入ってからは主に研究・バイト・落研の三本柱が全部中途半端になってよくわからない状況になり日々停滞している気がする。多分キャパをちょっと超えていてでも自分ながら情けないけどどれも手放せる気がしなくて、いつかなにかいくつかを握りしめながらどこかへ落ちていく気もする。代名詞の例文!下線を引きましょう。

 近況はこんなもんにして、そうすると書くことが本当にない。最近自覚したのだが、僕はメッセージの決まった文章を書くのは迷いなく楽しく書けるのだが、自分でテーマを見つける・考えるということが割と不得手だ。つまりレポートはいくらでも書けるが、小説なんかが全然書けない。クリエイティブの欠片もない!この歳になって主体性がないのかという悲しみがあるし、これが就活で今ガッツリと足を引っ張っている。でも仕方ないじゃないですか、まあ多少は訓練でどうにかなるけど訓練してこれだし、やっぱり人によって生得的な得手不得手はあるんですよ。仕事ができる程度には主体性がありますよのエピソードを生成して乗り切るしかないし、実際仕事で真の主体性がどの程度求められるかと考えると甚だ疑わしいのでまあそんなもんでいい気もする。仕事ってふつう抽象度の高低はあれど何らか目的が与えられるし目的に向かう行動を考えて実行するのは別にできるんですよ。その一部でしかない問題発見能力・状況改善への行動の迅速さのことを主体性って呼ぶの、頭悪いのでやめたほうがいい気がするんだけど。

 思えば僕はいつもテーマがないと嘆いていた気がする。小中高のとき自分の好きなものがよくわからなくて漫然と時間を過ごしていたらその時代は本当にそれで全部終わってしまった。高校3年生になって急に受験に目覚め、第一志望合格というテーマを見つけられたのは本当に幸運だった。高校3年生の受験勉強漬けの期間は間違いなく辛かったが、前よりいくぶんわかりやすかった。
 大学に入るとこれまた本当に何もなくなってしまった。受験のとき僕は物理に適性があると思っていたのだが、残念ながら二次試験の当日に勘違いに気づいた。こうしてまっさらな未定の一年生として入学した。
 適当に授業を漁った挙げ句に情報科学というテーマを見つけたのもやっぱりこれまた幸運だった、だったにすぎない。そして情報科学のなかから低レイヤというかりそめの方向性を見つけ、そこに邁進している風を装って今までのうのうと生きている。僕は自分のこれが本物ではないと知っているし、休み時間はコントローラーを握る。
 人生にテーマを見つけられたひとは無上に幸運だと思うし、早くそれになりたいと思っている。テーマがないとブログに書くことが自分語りしかない。いま記事一覧を見てげんなりしているところです!

 随分散漫だったがそろそろ畳もうと思う。5000文字ってさらっと書ける分量じゃねえよ。2500文字くらいしかないけど許してほしい。というかいま見返すと本当に散漫でひどいと思う。まあ僕の人生にくっついている細かいやるせなさをぽろぽろ払って拾い上げただけなので面白い形にならない。なんかテーマくれれば一塊を提示できると思うんでtwitterで投げてもらってもいいですよ。僕はこのようにして募り結局書かなかった過去をうずめてその上に生きています。

 ここまで読んでくれた人いらっしゃるかわからないんですけど、もしいらっしゃったら本当に感謝したいです。こんなものをここまで読んでくださるとは。そんな感謝の気持ちを込めて、一つだけ有益な情報を書かせていただきます。

お題「#買って良かった2020

 発表!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 

 急に何?

 いや、なんかはてなブログって日替わりなのか何なのかわからないんですけどお題を出してくれてるんですよね。機械的に出されたお題なんてと思っていたけどそれでもあると凄く良いですね、縋っちゃうなあ。優秀賞はアマギフかなんかもらえるらしいのでこの文章を読んだ皆さんは各自この文章を優秀だと思ってください。

 ところで有益情報と申したのは嘘ではなくて、この枕はお題の通り僕のこの1年の買い物の中で間違いなく一番良いものでした。元々安い枕を使ってたせいかもしれないですが、寝付きが信じられないほど良くなった。毎日安定して体感半分程度の時間で寝られる。勿論人によって合う合わないあると思うのですが僕には凄まじい効果がありました。なんかストレートネックの人には特に良いらしいって噂を聞いたけど噂なので知りません。以上有益情報でした。いかガシガシ弟子でしたか?

 そんな感じです。もう書くことないな。というわけで、さっきまで散々言ってきたけどもう一度。

 書くことがない。

(おわりです)

人生で五指に入るボカロ曲

 今日めちゃくちゃ頭が痛くてなにもできない。なにもできないのでtodoとかは全部諦めて好きなことをやろうとした結果これをやることにした。結局僕は音楽の知識とかが今でも全然ないので音楽的なことは一切言えなくてしかも歌詞にもそんなに興味がなくて歌詞に感動したとかそういう事もあまり言えないので曲をただ並べるだけになるんだけど、まあなんとか並べた。全然関係ないんだけどこういう記事を本当はもっと書いていきたい、好きな曲なんてその時々で猛烈に移ろってゆくのでそれのスナップショットを撮っておくと後で嬉しくなったりするんじゃないかと思う。どうなんだろうね。でも自分の過去のブログとか見ないなあ。

 そういうわけで今この時点で選ぶ僕の人生で五指に入るボカロ曲を並べましたどうぞ。順番は思いついた順なので適当。6曲あります。

人造エネミー

https://www.nicovideo.jp/watch/sm13628080

カゲプロの曲の中では一番好きかなあ。カゲプロが流行ってた頃僕は逆張りオタクで、「ガキくせ〜〜〜〜」とかいいながら忌避していたせいでカゲプロの物語はほとんど追っていなかったし今でも知らないんだが、それとは関係ないものとして曲はかなり聴いていた。知ったのがカゲロウデイズだったこともあって最初の4曲を特に繰り返して聴いていて、その中で結局一番印象に残っているのがこれだったりする。曲全体に漂う寂寥感と虚無感と諦念がすごくいい。「それが最善策じゃないことを きっと君は知ってる」というフレーズは流石に心に残ってしまう。

めめめめめ

https://www.nicovideo.jp/watch/sm23815763

割とこう「とっておき」の曲だったりする。サビに入るまではしっとり抑えめという感じなんだけど、サビがめちゃくちゃいい。これも曲全体にかなり諦念のようなものが漂っていて、そういうのが好きなのかもしれない。この曲は大学に入ってから知ったんだけどどういう経緯だったか忘れてしまった。アイワナじゃないんだよな確か。知ってから結構長い期間これに支配されていたし、今でもこれは一番かもと思う。

とおせんぼ

https://www.nicovideo.jp/watch/sm7357463

これは思い入れがめちゃくちゃ深い曲、なんてったって一番最初に知ったボカロ曲なので。最初ボカロ曲というのは放送委員が流してくる耳障りかつ気まずくなる曲という忌避の対象だったんだけど、I wanna be the Revolutionをプレイしていたらこの曲に出会った上にめちゃくちゃハマってしまった。僕は結局アイワナプレイヤーとしては全然大したことなかったんだけど、耐久アイワナの動画を大量に見たおかげでそこから随分多くのボカロ曲を知ることができた。アイワナがなければ僕のボカロ趣味はなかったもしくは広がらなかったので、アイワナにはかなり深い感謝がある。曲自体は思い入れが深すぎてもうなんて言っていいかよくわからん。歌詞のニュアンス未だに全くつかめてないんだけど、つかめない人の曲なのかもしれない。wowakaさんは今でもすごく好きなアーティストです。

秘密

こういう曲名なのではなく単に人に教えないというだけです。じゃあ書くなよという感じですがその通りなのでその点に関して特に言うことはない。耐久アイワナ聴かなければなければ絶対知れなかった曲で、高校の頃はこれととおせんぼばっか聴いてた気がする。

マインドイブ | サイコセンス

https://www.nicovideo.jp/watch/sm32924916

https://www.nicovideo.jp/watch/sm30743292

これどういう意味かというと2つの曲です。いや絶海さんの曲の中から1曲かな〜と思ってたんだけど全然絞れんかった。僕にはすごく好きなアーティストが2人いて、wowakaさんと絶海さんです。この曲はどっちも歌詞は一昔前の厨二病かってくらい暗かったり悪魔的(そのまま)なんですが曲のテンションが異様に高くて、その齟齬がある種狂ったような印象をもたらしていてすごく好きです。あとこのキンキンするような感じの調声がめちゃくちゃ好き。どうしようね。

この曲も何で知ったか全然覚えてないなあ。大学に入ってからだし耐久アイワナではない。僕は高校までの頃はCD売ってるブースに行くとかそういう文化を知りもしなくてwowakaさんの姿を見られずじまいで後悔があるんだけど、その後悔を生かして絶海さんには超会議で一度お会いしたしサインCDも持っているので最強です。

 

こんな感じか。6曲出したけど実質5曲なのでセーフ。最初はもっと12曲くらい挙げてハミ出芸をしようとしてたんだけど「五指」を意識すると意外となかった。どうも僕の脳内では五指のごくわずか下の「五指ではないけど人生曲」みたいなとこに100くらいの曲がある感じの分布になってて、「これを入れるなら他100曲も入れる必要が出てくる」みたいな感じで外したのが多かった。その中でも、明らかにいい曲なのはわかってるけど思い入れ補正が足りない曲の群(砂の惑星ドラマツルギー、乙女解剖、ハウトゥー世界征服あたり)と、個人的にめちゃくちゃ気に入ってるんだけどこれは思い入れと思いたいだけなんじゃないかという謎の疑念がストッパーしてくる曲の群(さよならワンウェイハート、才能シュレッダー、グーパースターあたり)の2種類があるっぽい。自己分析ですね。まあこれ個人的思い入れ補正ランキングなので……。

どうでもいいけど最近僕はボカロをめっきり聴いていなくて(粗品の曲だけ聴いたけど)、自分の中の音楽を聴くためのリソースというのは全てytpmvに向けられている。のでめちゃくちゃ久々にボカロを聴いたんだけどめっちゃいいですね。また戻ってきてしまうかもしれなくてやばい。やばくないけど別に。まあ最近ボカロ聴いてないせいで思い入れ補正ランキングにするしかなくて無難な選曲になってしまったんだけど、本当は「今ハマっている曲」とかにしたほうがスナップショットという目的は果たせるしそっちのほうが面白い曲を紹介できるのでそういうのもやりたいですね。ちなみに僕の文章におけるやりたいというのはやらないという意味です。

本当にどうでもいいけどここまで書いたことにより頭痛が完全に治った。自分語りは頭痛にいいってマジ?どうせ書くならもうちょいマシなものを書きたいんだけどなあ、小説書くのとかやりたい……。ちなみに僕の文章におけるやりたいというのはやらないという意味です。

(おわりです)

OCaml print tips: %a, Format module

こんにちは納豆です。18erです。

この記事は

ISer Advent Calendar 2018 - Adventar

の11日目として書かれました。昨日はlmt-swallowさんの

SIS (SHE IS SUMMER) を語る – やっていく気持ち

でした。

概要

わりと19er向けのテーマなんですが、来年の関数・論理型プログラミング実験/コンパイラ実験のときに知っておくとちょっとだけ嬉しいかもという話をします。具体的には、その時使うであろうOCamlという言語で何かを出力する時に使えるちょっとした知識、「%a」と「Formatモジュール」のお話をします。今はそもそもOCaml触ってないしピンとこないよという場合でも、この記事の存在だけ覚えておくとちょっとしたお役立ちが生じるかもしれませんし、もしくは生じないかもしれませんね。排中律

導入

3年の冬学期にあるコンパイラ実験という講義で、「MinCamlを改造し、Syntax.t や Normal.t等の中間結果を出力できるようにせよ」という課題がありました。ここではこの課題のかわりに、Syntax.tをざっくり簡略化した以下の型を出力してみましょう。

type t = 
  | Int of int
  | Add of t * t
  | Sub of t * t

死ぬほど単純化しました。3人くらい死んだ。で、どういう出力が欲しいかというと、適度にインデントされてるやつが欲しいわけです。

ADD
  ADD
    INT 1
    INT 2
  INT 3

こういう感じですね。リアス式AST。これをocamlでどうやって実現するか?という話です。

そもそもの話として、ocamlにはvariantを出力するための汎用的な関数みたいなのが存在しません。しかも今回はいい感じにインデントもしたいわけです。そうすると当然、地道にパターンマッチしつついい感じに整形する関数を手書きすることになります。

let rec print_space n = Printf.printf "%s" (String.make n ' ')

let rec print_syntax_sub indent e =
  print_space indent;
  match e with
  | Int(i) -> Printf.printf "INT %d\n" i
  | Add(e1, e2) ->
      Printf.printf "ADD\n";
      print_syntax_sub (indent + 2) e1;
      print_syntax_sub (indent + 2) e2
  | Sub(e1, e2) ->
      Printf.printf "SUB\n";
      print_syntax_sub (indent + 2) e1;
      print_syntax_sub (indent + 2) e2

let print_syntax e = print_syntax_sub 0 e

(t型の値にeという名前を使っていますが、expressionのeです。)
そんでもって、これは特に問題なく動作します。ということはこれでいいわけでして、実際僕はこれと同じようなものを提出しました。
ただこのやり方だとAddとSubで同じようなことを書いているのがかなりキツいです。というのも、簡略化されていないSyntax.tというのは

type t = (* MinCamlの構文を表現するデータ型 *)
  | Unit
  | Bool of bool
  | Int of int
  | Float of float
  | Not of t
  | Neg of t
  | Add of t * t
  | Sub of t * t
  | FNeg of t
  | FAdd of t * t
  | FSub of t * t
  | FMul of t * t
  | FDiv of t * t
  | Eq of t * t
  | LE of t * t
  | If of t * t * t
  | Let of (Id.t * Type.t) * t * t
  | Var of Id.t
  | LetRec of fundef * t
  | App of t * t list
  | Tuple of t list
  | LetTuple of (Id.t * Type.t) list * t * t
  | Array of t * t
  | Get of t * t
  | Put of t * t * t
and fundef = { name : Id.t * Type.t; args : (Id.t * Type.t) list; body : t }

という感じ。AddSubFAddFSubと延々コピペもどきが続くことになり、まあ憂き目なわけです。

この重複を除きたいということで、「variant名の出力」と「インデントの整形」を分離するのは自然です。

let rec print_space n = Printf.printf "%s" (String.make n ' ')

let ename e =
  match e with
  | Int _ -> "INT"
  | Add _ -> "ADD"
  | Sub _ -> "SUB"

let rec print_syntax_sub indent e =
  print_space indent;
  match e with
  | Int(i) -> Printf.printf "%s %d\n" (ename e) i
  | Add(e1, e2) | Sub(e1, e2) ->
      Printf.printf "%s\n" (ename e);
      print_syntax_sub (indent + 2) e1;
      print_syntax_sub (indent + 2) e2

let print_syntax e = print_syntax_sub 0 e

こうなります。いい感じですね。ほんとはここで「これだとあんまよくないですね、こういう時に使えるのが……」みたいに話を繋げようとしたんですが予想外にいい感じだったのでどうしようかなと思っています。まあともかく、これをもうちょっとだけ簡潔にする余地があるんです。

%a

printfの引数たる「フォーマット文字列」においての話なのですが、%dで数字を文字列の中に埋め込めるのと同じく、実は%aで任意のオブジェクトを文字列の中に埋め込めます。ただ、そのためには出力用の関数を一緒に渡してやる必要があります。この関数は「第一引数にチャンネルを、第二引数にオブジェクトを受け取る関数」です。ここは具体例で済ませますが、

Printf.printf "%d" 1;;
Printf.printf "%a" (fun oc i -> Printf.fprintf oc "%d" i) 1;;

この2つが等価です。
さて、これを使って書くとこんな感じになります。

let rec space n = String.make n ' '

let ename e =
  match e with
  | Int _ -> "INT"
  | Add _ -> "ADD"
  | Sub _ -> "SUB"

let rec pr_e indent oc e =
  match e with
  | Int(i) -> Printf.fprintf oc "%s%s %d" (space indent) (ename e) i
  | Add(e1, e2) | Sub(e1, e2) ->
      Printf.fprintf oc "%s%s\n" (space indent) (ename e);
      Printf.fprintf oc "%a\n" (pr_e (indent + 2)) e1;
      Printf.fprintf oc "%a" (pr_e (indent + 2)) e2

let print_syntax e = Printf.printf "%a\n" (pr_e 0) e

%aをやるために無理やり部分適用とかしてしまった。わかりやすいかと言われるとあんま変わらないなという感じですが、まあ出力がフォーマット文字列と関係ないところで起こらないという点では統一感があるのかも。

Formatモジュール

上のやつでちょっと不満なのが、インデント情報が目につくというところですね。ここをもっと簡潔に書けないでしょうか。書けます。Formatモジュールを使いましょう。

Formatモジュールについてですが、「日本語の解説がマジで無い」という特徴があり、しんどいです。というわけで、英語の文書として公式チュートリアルの解説公式ドキュメントに当たります。前者は概要編、後者は詳細編という感じですね。以下あんま詳細には立ち入らないですが、概要編の中身を要約してお伝えします。

まずFormatモジュールのすごく重要な概念として、下の2つがあります。

  • boxes
    そのまんま「箱」です。箱は出力からは直接は見えない論理的な区切りで、入れ子にもできます。Formatモジュールは基本的に、「箱をopen」→「箱の中でいろいろ出力」→「箱をclose」という感じで使います。箱の嬉しいところは、「箱の中で改行すると箱の先頭と頭を揃えてくれる」「箱の中で改行したときの追加インデント量を箱ごとに設定できる」という点です。先のSyntax.tの出力に使えそうですね。
  • break hints
    これは「区切り」です。boxの中でbreak hintを出力すると、Formatモジュールがいい感じに判断して「改行」か「スペース」かを選んで出力してくれます。上の例だとあんま活きないですが、このいい感じの判断こそがFormatモジュールの売りみたいです。

いちいち箱をopenしてわちゃわちゃというのはめんどくさそうですが、実際にはFormat.printfとかの整形出力関数においてはこれらの動作を表すアノテーションがあるので、簡単なケースならラクできます。具体的には、 Format.printf "@[hoge@ fuga@]" とかやると、「箱をopen」→「print_string "hoge"」→「break hint挿入」→「print_string "fuga"」→「箱をclose」という意味になってくれます。

以下、これらについてもう少しだけ。

Boxes

箱には種類が4つあって、それぞれbreak hintsの扱いが違います。

  • horizontal(h)
    絶対改行しないマン
  • vertical(v)
    絶対改行するマン
  • vertical/horizontal(hv)
    改行なしで全部いけるなら改行しない、無理なら全部改行するという極端マン
  • vertical or horizontal(hov)
    右側スペースに余裕があるときは改行せず、余裕がなければ改行する。空気読めるマン

下のプログラムではvを使いますが、基本的にはhovが標準という想定らしいです。箱の種類はアノテーション@[<hov 1>みたいな感じで指定できます。(数字は「箱の中で改行した時の追加インデント量」です)。@[@[<hov 0>と等価です。

Break Hints

@;<n m>で、「改行されなければn個のspace、改行されたらm個のspaceで追加インデント」という指示となるbreak hintを挿入できます。この「改行された時のインデント量」はboxとは別に持っていて、実際に改行されたときはboxのものとの和になります。

あと@, ( = @;<0 0>), @ ( = @;<1 0>)というアノテーションもあります(後者は@の後ろにスペースです)。

使ってみる

let ename e =
  match e with
  | Int _ -> "INT"
  | Add _ -> "ADD"
  | Sub _ -> "SUB"

let rec pr_e ppf e =
  match e with
  | Int(i) -> Format.fprintf ppf "%s %d" (ename e) i
  | Add(e1, e2) | Sub(e1, e2) ->
      Format.fprintf ppf "@[<v 2>%s@,%a@,%a@]" (ename e) pr_e e1 pr_e e2

let print_syntax e = Format.printf "%a@." pr_e e

さっきocだった部分がppfになっているのは、Formatモジュールではout_channelの代わりにformatterというものを使って出力を行うようになっており、これの慣習的な名前がppf (多分pretty print function)だからです。formatterは出力先以外にも右側マージンの大きさとか同時にopenできる箱の総数とかFormatモジュール固有な情報を含んだ型みたいです。まあfprintfにそのまま渡せばいいので今回は関係ないですが。
あと@.は「箱を全部閉じてバッファをフラッシュして改行」を表します。

結果として、フォーマット文字列以外の部分は簡潔になったかなという気がします。でもフォーマット文字列がアノテーションでごちゃっとするので総合的には微妙な気がしますね。

最後に

有益情報を提供したかったのだが、思いの外使いやすくもなかったので豆知識紹介おじさんみたいになってしまった。
明日はtera_poonさんです。

(おわりです)

コミケに行ってきました(C94)

朝起きて、少し朦朧としている時間。それは、取り戻すための時間なのかもしれない。
空っぽで抑圧された鈍い頭に、自分の使命を蘇らせるための。

目覚めた瞬間の意識というのは、産まれたばかりと同じようなものなんだと思う。
なにもないし、なにもわかっちゃいない。
だから、束の間開放されていた自我を、ちゃんと自分に縛り付ける営みを。

8月10日、朝起きて、少し朦朧として。そして取り戻して、今日は何も予定がないことを知る。
どうするかな、と青い鳥を眺める。
そして、




コミケ行ったことねえから行ってみっか!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!」




と思いました。

思い立ったが吉日って言いますよね

いやまあ朝起きたら予定ないしコミケでも行ってみっかって気持ちになったというだけの話なんですが、国際展示場です。

まず駅に着くまでなんですが、もう既に人がいっぱいいる。最寄りじゃないとこの駅で列みたいなのができてやがる。
まあでもそんなにすごいことにはならず、国際展示場駅に到着。
展示場駅はなかなか凄く、人間が大量にいた。大量にいすぎてびっくりしたけど写真は撮りそびれた。ほげー。

ところでコミケの入場って「ザ・列」みたいなイメージをtwitter経由で持っていたのですが、実際のところそれは大量の開場待ち勢が入場し切るまでの10:00~12:00くらいの話で、それ以降は別に一切並ばずとも普通に入場できるんですよね。人がいっぱいいると言ったけど、通路がそれなりに広いので待つ感じではなかった。まあそういうわけでわっちゃわちゃですね。

ところでテンションが上りまくってツイートをいっぱいしていたので、ここからはツイートを軸に振り返っていきます。

コミケは暑いという100億回リピートされた話題があり、でも別に炎天下屋外待機勢がキツいというだけで入ってしまえばそんなでもないだろうと勘違いをしていたのですが、完全に甘かった。確かに屋内だし日光的なキツさはないのだけど、尋常じゃない量の人間がいるので人間の熱で暑いんですよね。あと普通の屋外の暑さとは違って妙に湿気のあるムワッとした暑さで、なんか体力を奪う感じがあるというか、これは慣れてないとだいぶ不快だった。慣れればそんなでもないんだけどね。ただ行ってみて初体験で予想外の現象が起きるとダメージがでかいという話があり、割と早い段階で消耗してしまった。ポカリもすぐ使い切った。
あと↑のツイートを見ればわかるように明らかに迷ってるんですが、これは会場mapとかを一切見ずに人の流れに身を任せていたからです。

周遊していたらブースに着きました。ブースっていうのはなんか机が大量に並んでいて人がモノ売ってるゾーンで、つまり本質です。 別の同人誌即売会には行ったことがあって、方向性というか質的雰囲気はそれとほぼ変わらなかったのですが、人間の量が段違いなのでそこは体験に違いを及ぼしますね。基本的にみんなエネルギーを放っているのですが、延々広がっているフィールドで大量の人間がエネルギーを放っていると謎の一体感が出ます。

これは知らん。

これはすごかった。200円。ちなみにこれラス1だったらしい。 どういう本かというと、はじめと終わりに1~2pくらいの漫画があり、中身は霊夢口調でびっしり字で民法の説明をしているというものです。「これアリなのか、同人の世界は本当になんでもあるな」という驚きの気持ちもあった。口調以外はほぼ完全に民法の話なのですが、ちゃんと初心者が読むのを想定した文章なのでなかなかわかりやすくためになります。これはかなりいい買い物をした。

この人は前からtwitterで知っていたのですが非常に好きです。2個目のツイートの右上のページとか特に好き。くすぐりのセンスというか、漫画の運び方みたいなのが好きです。つまり一番いいやつですね。冊子も別に書き下ろしがいっぱいあるやつではなかったのでお布施という気持ちを持っていきました。でもせっかく手に入ったのでtwitterでも読めるとはいえ何回も読み返している、買ってよかった。

ここからモリモリ周遊しました。コミケは大雑把に言って東棟と西棟に分かれていて、東を見尽くしました。 完成閾値バリだったので何も買わなかったけど、正直危ないシーンは何度かありました。僕は東方・vtuber・undertaleにかなり弱く、東方は規模のデカさにより「これを買っていたらキリがなくなる」バリアを使えたのですが、vtuberとundertaleにはそれが効かないのでやばかった。

あとこれは東→西への移動中の出来事です。


というわけで西をガン見していきます。 割と同人誌主体っぽかった東とは違い、西は「その他系」っぽい雰囲気でした。西の中で一番存在感がデカかったのは「音楽」で、とにかくCDをいっぱい売っていたのですが、これに関しては表紙買いを僕はしないし試聴もしなかったのでサーッと通過しました。あと西で存在感があったのは技術系書籍ですね。割とパソコン触ってる系の人たちが「サーバの作り方」とかそういう系統の本を出しているゾーンがあって、正直そこはなにか刺さるものがあれば買おうかなと思っていたのですが、なんだかんだニッチかつレベルの高いものが多くて普通に手が出なかった。ただ興味深いタイトルのものは結構多くて嬉しくなりました。このへんでぱてゼミのブースに行ったけどぱてさんがいなかったので、あとで来ようという思いを残して移動。

そんなこんなで西もざっくり一周。あと行っていないのは、西・東の企業ブースです。もう時間としてはギリでしたが、行きたいという気持ちがあったので西の企業ブースにgo。企業ブースは時間が長いっていうことを知らなかったのですが、企業ブースは時間が長かったので、まだやってました。企業ブースはでかくて色々あり、いかに自分が最新のアニメを知らないかということがビシビシわかりました。このへんで時間は切れたのですが、東の企業ブースに絶対行きたかったのでぱてゼミをスルーし移動。 そしてついに。

キルミーベイベーは神
ところでこのシャツを普段遣いできるようになればこれは浪費ではなくなるので、コーディネートを考えています。

企業ブースもガッツリ見たのでぱてゼミはもう撤収してるかな、でもぱてゼミのことだしなとか思いつつ16:40頃にぱてゼミのブースに行ったらいました。他がほぼ全部撤収完了してる中残っていたのでちょっと笑ってしまった。作詞をちょいやったパワーによりCDをゲット、そして帰路につく。

まあ基本的にこれで、金を持っていれば絶対もっと楽しいと思いました。

これは知らん 何言ってんだこいつ

感想

よく言われることですがお祭りでしたね。欲しくなりうるものが一手に集約され延々と広がり、しかも周りの人間の熱気がかなりあり、何かしらのスイッチが自分の中で入るのがわかります。12:00くらいから16:30くらいまでほぼ完全に歩き通しでしたからね。僕は普段全然歩く人間ではないのですが、最中は疲労感より自分の歩みを進める謎の力のほうが勝っていました。

合氣道会の合宿に行かずにこれに行っていたのでこういう事も言いました。
でもみんながハード合宿やってる中ひとりで全力エンジョイしていたのは普通に申し訳ない気持ちだったので、その後反省のツイートを致しました。

(おわりです)

railsゆるふわリハビリ開発日記

ほんとにゆるいので、学科民が読んだら薄味すぎて死ぬんじゃないかな。やめたほうがいいよ!(予防線)(学科民が怖い)
 
目次

なんの文章ですか

なんか気分になって軽いrailsアプリを作ってみたので、作業ログというか気持ちの日記みたいなのを公開してみます。マジでただの気持ちなので誰の役に立つかというのはよくわからないのですが、railsでなんかやってみたいけどイメージ掴めないなという人にはいいかもしれません。あとまあactive storage使ったのでそのへんかな。

なんのアプリですか

pdfをアップロードするとjpegに変換して一覧表示してくれる&最終閲覧順に勝手に並んでくれる というアプリです。気持ちとしてはスマホでpdf見ようとするとダウンロードされる上にその後ローカルで迷宮入りしてクソうざいという現象があり、webで一元管理できたらいいよなあという気分になったというのがあります。

……とか言いつつ、これ本気でやるならモバイルで開発してファイルのアップロードを楽にするべきなのでこういうwebアプリとしてやる意味は特になく、単にrailsの練習がしたかっただけです。railsはn年前くらいに一通り学んだのですがそれっきりで記憶が風化してしまったのでリハビリをしたく、また単純なCRUDを作るだけなのも味気ないなと思ったのでファイル処理でもやろうという気持ちになったというのがあります。まあただのトレーニングというわけですね。

ちなみにモノですが、こちらになります。
github: https://github.com/iwannatto/mypdfviewer
heroku: https://mypdfviewer.herokuapp.com/pdfs

※herokuの方は触る前に下の方にある注意事項を読んでください

環境構築編

まあ手持ちはmacだしできないってことはないやろ、粛々とやっていきまーす……

とかナメてたらドブった。どうもrubyのビルド時にopensslの場所を正しくお伝えしなければならない様子なのだが、./configureのオプションでお伝えしたはずなのに一切うまくいかない。いろいろ試してググってグネグネやってようやくrailsが入れられてセーフと思ったら、「rails s」をするとセグフォするという最悪の状況が出現。ここで更にググったけどなんかopenssl自体の入れ直しを迫られて非常に嫌になり、結局cloud9に逃げ込む。(もともとアカウントは持ってた)

cloud9にしたら1分でいけました。

結論:ローカルはクソ。時代はクラウド

アプリ全体について考えてみる編

要件としては「pdfをアップロードし、jpegに変換して表示できる」「最終閲覧順に並べられる」というものなので、これを満たすにはどうすればいいかを考えます。
まず最初の要件に関して、ファイルを受け取って保存できる必要がありますね。ちょっと調べてみると、最新のrails5.2には「active storage」というファイルを扱う用の枠組みがあることがわかりました。まあ普通にこれでオッケーそうだし、最新機能というのは響きがいいのでこれでいくことにしました。
もう一つ、pdf→jpegの変換ですが、これはimagemagickという一般的なソフトウェアで普通にいけるらしいということがわかりました。rubyからimagemagickを触れるようなgemがある(minimagick)ので、たぶんこれを使えばオッケーでしょう。
あとは最終閲覧順に並べるというのですが、これは単純に最終閲覧日時のカラムを用意すればそれでよし。
というわけでなんとなくやることが決まりましたね。

pdfを受け取る編

まあ骨組みから作っていくわけですが、railsはscaffoldingとかいうハイパー骨組み作成機能があり、ちょちょっとやるだけで基本的なCRUDを備えたMVCが全部できちゃうんですよね。

$ rails new mypdfviewer
$ cd mypdfviewer
$ rails g scaffold pdf name:string last_access:datetime
$ rails db:migrate

 これでもうできました。この段階ではまだnameとlast_accessしか扱えないのですが、それでももうこの時点でアプリケーションとしては動作するんですよね。ほえー。
というわけでCRUDができてしまったので、あとはこのpdfモデルでpdfファイルを扱えるようにしてやればよいです。
まずconfigを弄る必要があるんですが、なんか自動生成されたconfigそのままで問題ないっぽいのでよし。
モデルを弄るのは超簡単。

# app/models/pdf.rb内のクラス内に追記
has_one_attached :pdf

この1行を入れるだけでpdfという項目名でファイルを扱えるようになります。ウオー。
あとはformにfile_fieldを入れてファイルアップロードできるようにして、ストロングパラメーターの部分だけいじれば、
「@pdf = Pdf.new(pdf_params)」みたいな普通の記述でpdfモデルへのpdfファイルの紐付けができてしまいます。
というわけでこれにて終了。なんというか、圧巻の簡単さですね。すごいなあ。

ちなみに、DB触らなくていいの?となるかもしれないのですが、active storageはDBではない場所にファイルを保存するので、これ以上DBを触る必要がないんですよね。ただ、内部的にはメタデータを扱うためのDBを作るようなので、一度なんかのコマンドを走らせる必要だけあったかも(忘れた)。それと、今回はローカルに保存する設定になっていますが、その気になればS3とかが使えます。

あとついでに、ファイルの中身をpdfに制限したいので、モデルにバリデーターを作ったりもしました。これは後に間違いであったことが判明します。

pdf→jpeg変換編

とりあえずimagemagickを入れます。これ後で本番環境に入れるの忘れそうで怖いな。

$ sudo yum -y install ImageMagick

gemとしてはminimagickを使います。railsのscaffoldingで生成されたデフォルトのGemfileに書いてあるからという安直な採用理由で。

# Gemfileのmini-magickの行のコメントアウトを外す
$ bundle install

あとpdfモデルにjpegを付与できるようにしておく(モデルに1行追記

ここまでやれば、あとはminimagickを使って変換処理を書けばいいんですね。
……ところがここでハイパー詰まります。active storageにもminimagickにも不慣れなせいで、ファイルの取得・読み込ませ・変換 の各段階でガツンガツン引っかかった。
まず入力、imagemagickで拡張子変換をするのにはconvertコマンドを使うのだが、minimagickでそれに対応する(と思っていた)convertオブジェクトは入力でパス渡しをしなければいけない。ところがactive storageから取ってきたファイルはちゃんと使えるパスがないっぽく、わりと調べたが?????となり、結局今回はconvertオブジェクトは使えないということに。active storageからpdfを読んでそのバイナリを取り出してimageオブジェクトというのに渡し、そこでメソッドで変換するらしい。
取り出しにもなんか一癖あり、active storageへの保存メソッドにはストリームを渡す必要があるため割と考えなければいけなかった。最終的にはimageオブジェクトからはstring型でデータが取り出せるのを突き止め、そいつをrubyのstringioを使ってストリームにして渡しました。これstringioのことを元から知っていなければ詰んでいた感じがある。

require 'mini_magick'
require 'stringio'
binary = @pdf.pdf.download
pdf = MiniMagick::Image.read(binary)
jpeg = pdf.format('jpeg', 0)
sio_jpeg = StringIO.new(jpeg.to_blob)
@pdf.jpeg.attach(io: sio_jpeg, filename: '0.jpeg', content_type: 'image/jpeg')

というわけでどうにか変換処理には成功。ただ、デフォルトの変換というのは画質が悪く、この画質を調整するには変換時にdensityオプションを指定する必要があるんですね。というわけで、そこを改良。

……しようとしたところでまた詰まるんですね。オプションを足すなんて簡単にできるのでは?という僕の考えは非常に甘く、上のやり方ではdensityオプションを正しく指定できない。これは「imagemagickのコマンドにおいて、densityオプションは入力ファイルの前につける必要がある」というのと「imageオブジェクトのconvertメソッドを使う方法では入力ファイルの後に付けるオプションしか発行できない」というのが合わさりですね……。これできないの全然信じられなくて相当ググり回ったんだけど、不可能らしいということを確認するに終わりました。
まあそういうわけでどうすんのという感じだったのですが、ここでさっき切り捨てたconvertオブジェクトが使えました。imageオブジェクトをバイナリから読み込んだ後は実はパスが発行できるようになるので、これを渡せばok。convertオブジェクトは入出力両方パス渡しなので出力をどうするかと散々悩んだのですが、結局rubyのtempfileを使えばいいじゃんという話になりました(ここで1時間くらい悩んでいたのは普通にアホだった)。

require 'mini_magick'
require 'tempfile'
binary = @pdf.pdf.download
pdf = MiniMagick::Image.read(binary)
Tempfile.create(["", ".jpeg"]) do |jpeg|
  MiniMagick::Tool::Convert.new do |convert|
    convert.density(600)
    convert << pdf.path
    convert << jpeg.path
  end
  @pdf.jpeg.attach(io: jpeg, filename: '0.jpeg', content_type: 'image/jpeg')
end

まあなんとかできました。この辺の時間対成果の低さはやばかったんですができてよかった。
ちなみにこの後ファイル入力の仕方が変わるので結局全部パスになり、結局バイナリ関連で調べたことは全部無駄になりました。フエーン

最終アクセス時間

普通に書いたら終わった。
この辺は箸休めだった。

各種改良編

まあそういうわけで↑の段階で一応要件を満たしてかつ動くものは作れたので、あとは気になるところをちょこちょこ直す作業に入ります。ざっくり2つありました。

まず1つ目は、現行のコードだと pdf受け取る→active storageに保存→active storageからpdf取り出す→jpegに変換 という動きになっていて、これは自明に無駄なので直します。まあこれはそもそもリクエストデータの中にあるファイルをどうやって扱っていいか調べるのがめんどいからごまかして書いてただけなので、最初からやるべき作業とわかっていたやつ。
これも結局調べて数行書いただけ。結論から言うと、リクエストデータの中にあるファイルは一時ファイルとなって保存されており、そのパスが普通に手に入った。というわけでimagemagickにはパス渡しだけしてればよくなった。

もう1つはバリデーションに関して。railsではモデルにバリデーションを設定することができて、データをDBに保存する直前に自動で検証してダメだったら差し戻してくれます。というわけでpdfモデルのpdf(ファイル)にも.pdf以外を弾くという簡易な拡張子検証を入れておいたのですが、サーバのログを見ているとあることに気づきます。
pdfファイルに関しては、どう見てもデータ保存した後にバリデーションが動いているんですよ。
そういえばactive storage周りを調べている時に「active storageにはバリデーションがない」という文言はいくつか見ていて、これは「デフォルトでactive storage用のバリデーションマクロがないから手動で書かなきゃいけない」程度の意味だと思っていたんですが、どうも動きが根本的に違うようで。試してみた結果やはりバリデーションはダメで、「active storageに対応する属性はセットした瞬間にsaveされてしまう」「このsaveの際にバリデーションは働かない」という仕様のようでした。一応後からバリデーションを走らせることはできるけど、二度手間もしくは無意味になると。
railsは基本的に「コントローラでバリデーションすると分厚くなるからダメで、モデルに書きなさい」という思想だったのでうーんという感じでしたが、最終的には大人しくコントローラにバリデーションを載せたら終わりました。ちなみにrails開発陣によるとactive storageのバリデーションは普通に今後実装する予定らしいですね。まあそうか。

heroku編

herokuにあげようとしたらimagemagickが入ってないなと気づく。
HerokuでImageMagickのconvertができるまで
↑をまんまやって終了。先人は神
と思っていたが、クラッシュしたり何なりがあったのでProcfileを書いた。この辺よくわかっていない。

完成品

github: https://github.com/iwannatto/mypdfviewer
heroku: https://mypdfviewer.herokuapp.com/pdfs
一応上げてみました。どうぞ。

herokuの方の注意事項を諸々と。

  • ユーザーとかの概念がないのでファイルは全部完全に公開されます
  • 上げたファイルが保存されている保証が全然ないです
  • ある程度でかいファイルを上げるとなぜかクラッシュします(は?)(具体的には100KB前後とかにしておいてほしい)

というわけでまとめると、試してみるなら「誰に見られても問題ない&バックアップのある&100KBくらいの」pdfにしてください。
あとこれセキュリティとかその辺一切考えてないので完全に善意頼りですヨロシク。

ちなみに先ほどファイルの保存を保証しないと言いましたが、もっと具体的に言うとファイルは勝手にバシバシ消えていきます。
詳細はここに書いてあるのですが、要はherokuサーバにファイルとか作ってもアプリが再起動すると消滅するというheroku側の仕様です。つまりherokuでactive storageをlocalで使うのはそもそもできないので、本来ならS3とかのストレージサービスを使うべきという話です。ただまあ即消えるわけじゃないので動作確認ならなんとかなるし、何よりめんどいということでこのままいっています。
ちなみにちゃんとS3とかにしたい場合はアカウント取ってconfigいじればいけるっぽいです。

感想

すべてを覆い隠すフレームワークの息吹を感じる。
いやほんとこれで、webアプリを作ったかと言われればyesなんでしょうが、プログラミングをしたかと言われれば気分的にはnoなんですよね。人の書いたものを使っている感がすごいというか、クソでかいconfigを延々弄っている みたいな気持ちになります。
と言ってもこれは決してdisっているわけではありません。むしろこれはおそらくrailsの目指しているものなはずで、良いことだと思います。モノが秒でできてほしいという人間に対して最適な方法を提供していると言いますか、スタートアップでガンガン使われるのは伊達じゃないなあと。実際、「rails」でtwitter検索をかけてみると、なんていうかウォッとなるような人間がいっぱい登場するんですが、そういう人たちが開発に参加することができるようになるからこそ強いんだろうなあ。この面では結局圧倒的というか、railsすげーという気持ちになりました。
あと個人的に気になるところなんですけど、railsを極めるとどういうエンジニアになっていくんでしょうね。railsに精通していくのか、あるいはrails自体の開発に噛んでいくのか。ちょっとググった感じ、この記事みたいな感じの見通しなんでしょうかね。
まあともかく、作りたいものがあった時に強力なフレームワークであるのは間違いないなという気持ちになったので、なんかあったら今後もrailsで作ってみたいですね(ふわっふわ)。


(おわりです)

今週の実績解除:12時半の秋葉原

2限と3限の合間に秋葉原に行ってきました。

f:id:iwannatto:20180701180735j:plain

こんな感じ。真昼なのでめちゃ暑かった。チャリで行けるらしいという説を聞き、時間とかをよく考えずに適当に出発。「とりあえず適当に直線的に進む→Google Mapを見る→適当に直線的に進む」を繰り返すという天才的なアルゴリズムで向かったのですが、異常なほど坂を上り下りすることになったのでこのアルゴリズムはバカだと思いました。なぜか帰路の3倍くらいの上り下りが発生した。バカすぎて逆に天才なのではという説はあります。

残念ながら滞在可能時間が短いということもあり、特に見物するでもなく用事を済ませ、飯を食べて帰りました。飯がこちらになります。週刊食べログ

f:id:iwannatto:20180701180938j:plain

アキバ盛りカレーという商品名で、完全に商品名インパクトにやられました。いやだって、「アキバ」という単語をそこにかけるか普通?そして妙に語感がいい。こういうパワーゴリ押し系ではない名前でインパクト出せるのはセンスなのでは?と思います。

味ですが、軍でした。カレーって基本的には統一・洗練っていうイメージの食べ物ではなくて、刺激物やうまみ等が各位暴れていくことによって人々を笑顔にする食べ物だと思ってるんですけど、その路線の極致みたいな味がしました。2色のカレー、両方スパイシーでかつ味が全然違うのでこの時点で大暴れという感じですし、具の統一感のなさもすごく良くて、手前から食べ進めていくと要所要所で攻めてくるんですけど、これはゲームで言うイベントですね。アキバ盛りってそういう意味なんだろうか?だとしたら深すぎる。とにかく広がりというか物量で叩き潰しに来る最高の味で、「これは袋叩きですわ」「多勢に無勢ですね」「こっちは一人しかいないんだけどこんなやる?オーバーキルじゃない?」みたいな感想が終始生えていました。途中で軍の視覚イメージとかも浮かんでたんですけど、今思うと槍投げで象を狩るアレの方が近いかなという気がします。

まあそんな感じです。店の居心地も良かったのでちょっとゆったりしてしまったんですが、出てからは多少急いで大学に戻ったので3限には-30分ほど余裕を持って間に合いました。

(おわりです)