2017年 - 買ってよかったもの
前々からやってみたかったやつやります。
Bose SoundLink Mini II
Bose SoundLink Mini Bluetooth speaker II ポータブルワイヤレススピーカー カーボン
- 発売日: 2015/06/26
- メディア: Personal Computers
今年の一番といっても過言ではないレベルでよかった。
昔からイヤホンは Bose 一筋できたけどリモートワークするようになってから自宅用にヘッドホンがほしくて、でも Bose は高いのでいろいろ調べて去年 Sennheiser の密閉型で安くなってるやつを買ったんですね。
【Amazon.co.jp限定】ゼンハイザー ヘッドホン 密閉型 HD 598 CS【国内正規品】
- 発売日: 2016/11/25
- メディア: エレクトロニクス
これ音が本当によくてめっちゃお気に入りなんですけど、ヘッドホンって何時間も付けてると顎が痛くなってくるのでスピーカー欲しいなと思ってたら、ついに、サイバーマンデーで17000円になってたので即購入しました。
仕事中でなくても自室の隣の部屋にあるこたつで過ごしてるときにひょいと持っていけるのが本当に便利。ほら相棒いくぞって感じ。
※ ちなみに Sennheiser は開放型のヘッドホン (通称プリン) の方が有名らしいです。私は使ったことないですが。
財布
もう在庫がないのかどのオンラインショップにもなかったので写真で失礼します…
それまで使っていた財布は大学生の頃から使っていてボロボロだったのと、もう現金をほとんど使う機会がないのでとにかく薄い財布が欲しかった。
この財布にしてから荷物が軽くなって肩への負担が減ったように思えるのがとても嬉しいです。
整理したけどまだ入りきらないカード (主に診察券…) は1000円くらいで買えるカードケースに入れて持ち歩いています。大きい財布に全部入れるより会計時にあたふたしないので薄い財布 + カードケースの組み合わせはとてもいい買い物でした。 shop.afternoon-tea.net
iPad mini 4
11月に同僚2人とパリへ旅行したときに勢いで買った。SIM lock free です。空港着いてすぐプリペイド SIM を入れれば、パリみたいな大きな都市ならネットから切り離される不安がないので便利でした。
あと出先で Github のレビューするのも iPhone 使うよりずっと便利でした。あとは買い物とか。
旅の話に戻ると、5年前にヨーロッパ周ったときはネットなんて宿でしか使えなくてもどうにでもなったのに、今では Google map を開かないとどこにも行けなくなってしまったことに気が付いて生命力の衰えを感じる旅でもありました。 (Google map があっても同僚2人が案内してくれないとダメだったかもしれない。。ありがとうありがとう)
NHK 大河ドラマ 平清盛 DVD
2012年の大河ドラマ。これの前半部はフィンランド行っててみれなかったので、帰国後後半部から見始めたらこれがめっちゃ面白くて夢中で最終回までみてた記憶があります。DVD 探しても在庫が全然ないしプレミア状態だったのが!今年ついに!再販しました!!!
欲を言えば BD が欲しかったけどそんなワガママは言ってられない。というか BD でたらきっとそれも買っちゃう。
KYOKA モバイルバッテリー
薄くて可愛くてめっちゃよかった。4回分くらい充電できる。
iniks
体調を崩しまくって肌が大荒れしたときにマスクをしながら成城学園前にある皮膚科へ行き、薬と共に勧められた化粧水 & 乳液。そろそろ基礎化粧品にお金をかけたいお年頃だったのでここで出会えたのは非常によかった。
1回2プッシュを朝晩2回で約半年くらいもつくらいの量です。が、半分くらい使ったところでこれ以外使う気になれなくなり、定期便を使うようになります。強いて言うなら SK-Ⅱ くらいかな (でもあれは馬鹿高いから…)。
すっぴんで外出るときにマスクしなくていいやー眼鏡曇るしめんどーいって思えるようになりました。
Aujua
絶対にネットで売ってくれないヘアケア商品。Aujua ソムリエという人たちがいる美容院でしか買えないです。
高くて毎回泣きそうになるんですけどドライヤー後に幸せな気持ちになれるのと、ちょっとずつ髪質変わってきてて使うのが楽しくなるので、パーマやカラーやってる人はぜひ。洗い流さないトリートメントだけでも全然違うので最初はそこからでも。
※ 洗い流さないトリートメントは今年11月のリニューアルで「ドライヤー熱による髪の老化防止」の成分が入ったらしくて特許取ったらしい (スタイリストさん談)。ちゃんと調べてない。
所感
今年は旅行やら買い物やらで去年に比べてだいぶ経済を回したという自覚が強い。ここに載せてない分だと服をたくさん買うようになった。痩せて着られる服がなくなったというのがきっかけだけど、やはり痩せると自分に投資してみたくなるものらしく、26, 7 の女性ってどんな感じなんだろうって随分と街なかを観察したりファッション雑誌を読んだりして参考にしてた (Hanako じゃなくて美人百花や Oggi を手に取る私をみて美容師さんがびっくりしてた…w)。
今回これを書くにあたって様々な購入履歴を漁ったんだけど、結局「よかった」と思いここに載せたのは「(私からすると) 高いから随分長い間迷ったけど結局買うと決断した」ものが多くて、迷ったら買え、は割りと正しいのかもしれないと思った。セールまで待つ、は今後もやると思うけど。
高けりゃいいってものでもないし、身の丈にあった生活を心がけることを最重要としているけれど、安物買いの銭失いにはならないように、2018年もたくさん経済を回していこうと思います。
中村屋ファミリー密着取材特番をみて考えたこと
テレビの年末特番で歌舞伎の中村屋ファミリー一年密着取材、みたいなのをやっていた。
歌舞伎は高校の何かの授業で観る機会があって、そのときは義経千本桜か何かだったんだけど役者がとても綺麗な所作をしていたのをすごく覚えてる。
小さい頃バレエをほんのちょっとだけやってたせいか、バレエも (ネットで) 観るのが好きなんだけど、とにかく動きが美しい。「人間ってこんなに美しく動けるんだ…」と食い入るように見つめてしまう。それと同じように歌舞伎を観たときも「ほう…」とため息が漏れるほど感動して、お金がなくて全然公演には行けてないんだけど、テレビで歌舞伎の特番とかやってるとつい見てしまったりしてた。
で、今回の特番。
話としては、中村屋は2012年に勘三郎さんが亡くなり、今年、勘九郎さんの息子の勘太郎さんと長三郎さんが初舞台を踏んだ。勘九郎さんと弟の七之助さんを筆頭として勘三郎さんの遺志を次の世代へ継いでいく、みたいな流れ。その中で自分が面白いなと思ったのはお稽古場の取材内容だった。
八月納涼歌舞伎の演目「野田版 桜の森の満開の下」。演出の野田さんは初日から千穐楽まで毎日毎日欠かさず「駄目出し」をするために勘九郎さんの控室を訪れる。
「駄目出し」というのは、公演をみた演出家が反省点・改善点を役者に伝えることなんだけど、野田さんの駄目出しはかなり多くて細かい。勘九郎さんはそれを一度聞いただけで全部覚えて、特に練習をすることもなくそのまま舞台へあがっていく。
19日間毎日毎日、そうやって駄目出しを繰り返して一つの舞台をより完成させていく。だから一日として同じ演技はないのだそうだ。
この内容をみたときに、不覚にも「あぁ、アジャイル…」と思ってしまった。これが社会人になったということか…やだやだ。
さて、野田さんの駄目出しを聞いてると
- 役者の演技をみて演技や台詞を変更する
- 盛り上がる場面なのに動きが小さく見えてしまってもったいないのでこういう動きをした方がいい etc.
- お客さんの反応をみて演技や台詞を変更する
- ウケ狙いの台詞にブレスを入れてみたらコミカルな雰囲気に反してしまって全くウケなかったのでブレスなしがいい etc.
の2パターンにだいたい分かれそうな気がした。野田さんの駄目出しには必ず、実際に自分で見て、お客さんの反応をみることで作られた根拠があった (実は他の人の駄目出しもそうなのかもしれないし、野田さんの性格なのかもしれないし、よく分からないんだけど)。
ただ、勘九郎さんがあれだけ膨大な量の駄目出しを一度聞いただけで覚えてしまえるのは、勘九郎さんの技量の高さや頭の良さ、経験の豊富さに加えて、この「根拠をきちんと伝えていること」ということも力を貸しているのではないかと、駄目出しされる前に「えーもうないでしょ〜」という勘九郎さんが、駄目出しされているとき「あ〜〜〜そうですね、そっか〜〜〜」と納得するその反応を見ていて思った。
- ディレクションする側は毎回きちんと自分の目やお客さんの反応を元に改善点を示し、プレイヤーを納得させる。
- プレイヤーは一度納得したら全てを自分のものにして最高のパフォーマンスを見せる (プレイヤー自身もお客さんの反応は見ている)。
これの繰り返し。回顧と反復。何かを作るということなんだなぁと思った。
この毎日駄目出しスタイルは勘三郎さんと野田さんが始めたことなんだそうで、年代的にも業界的も、きっと彼らは「アジャイル」だとか「PDCA」だとかいう単語は知らなかったんだろうと推測する。だけどとても近いことをやってた。厳しいお稽古に加えてこれをやるから、歌舞伎の舞はあんなにも廃れず美しいのかもしれないとか考えてしまった。
あんまりテレビ番組で心が動くということがないんだけど、今回は不覚にも思考を働かせてしまったので、せっかくだしこのふわっとした思考を綴っておこうと思った。回顧と反復というわけでもあるし、こういう雑な記事でいいのでイテレーション短くできたらいいな。
あと来年こそは歌舞伎を観にいこうと心に決めた。温泉で地方にいくついでに歌舞伎も観る。よさそう。
温泉一人旅 - 2017
この記事は 今年行ってよかったところ Advent Calendar 2017 18日目の記事です。
2017年は国内外問わずいろんなところを旅行した年でした。 国内・国外どちらの記事にしようか迷ったのですが、ここでは国内旅行に絞って書こうと思います。
発端
東京にいるととにかく人が多くて精神が摩耗してきて 山に…籠りたい… という願望が強くなってきます。加えて、今年の夏は大きなプロジェクトのリリースがあって身体も悲鳴をあげていました。
山に籠れて身体も癒せる場所…
温泉だ! ♨♨♨
ということで3日間の有給をいただき、急遽温泉一人旅へ。後述しますがこれがとてもよい旅で、それから人の多さに酔って山に籠りたくなると一人で温泉へ出かける、という生活をしていました。
今年行ったのは4箇所。
どれも大変癒やされる温泉だったので軽くですが紹介していきます。
万座温泉 (群馬県 吾妻郡 嬬恋村)
- 7/27 - 7/28 (一泊)
- 万座プリンスホテル
- 硫黄泉 (場所によっては温泉 1kg あたり 300mg 以上、ph2.4)
「満点の星空が見られる温泉」というようなキャッチコピーに惹かれて旅先の候補入りに。調べていくと「日本でいちばん硫黄含有量が多い温泉」とあったので、万座プリンスホテルを一泊二日で予約しました。
宿のサイトでこんな画像出てきたら行くしかない (万座プリンスホテル公式サイトより)。
それまで塩化物泉にしか入ったことがなかったので、硫黄泉というのも重要なポイントでした。
軽井沢
新幹線で軽井沢まで行き、そこからホテルのバスで1時間半ほど山へ入ったところに万座温泉はあります。山奥…!とても山奥…!これぞ求めていた山籠り…!
この頃心身ともに非常に疲れていたのでカメラを持っていくという思考が働かず写真が全然ないのですが、温泉宿以外何もないです。
ちなみに新幹線で寝過ごして長野まで行ってしまい、軽井沢で3時間のバス待ちをしました。軽井沢駅のすぐとなりにアウトレットモールがあるのでそこで洋服買ったりプリン食べたり、街中にある別荘情報を眺めたりして時間を潰していました。
温泉
女湯は内湯と露天の2種類と、混浴露天風呂がありました (男性側も同じような構成だったと思います)。混浴露天風呂は先ほどのホテルの写真のお風呂です。が、当日は曇り空で星空が見込めなかったので、夜に内湯、朝風呂に女湯の露天風呂へ行きました。
足を入れた瞬間分かる、硫黄濃度の高さ…!
硫黄濃度が高い (= 強めの酸性) ので古い皮膚が溶かされてすべっすべになるのだそうです (※ 皮膚が弱い人は長時間浸かってると危険です)。本当に、びっくりするほど一瞬で肌がすべすべのつるつるに。
朝風呂でいった露天風呂はなんと私一人しかいなくて貸し切り状態に…! 露天風呂の方が硫黄濃度が少しだけ低かったような気がします。色も内湯ほど白濁していませんでした。もしかしたら時間によるのかもしれませんが。
目の前に山があって、一人で温泉に浸かって、肌もすべすべで。
生きててよかった〜って思いました。
食事
この旅で思い出深かったことの一つに、宿の食事があります。
例によって写真がないのですが、それはこの時期疲れすぎていたため、この温泉旅を「旅」というよりも「療養」と位置づけていたからです。身体が弱っていて何も口にすることができずにいました。
そんな状態だったので、宿の夕食はレストランのコース料理ではなく、ビュッフェ形式を敢えて選びました。ビュッフェなら食べられる分だけ取ればいいので。
ところが、このビュッフェが何を食べても美味しい。
万座温泉は群馬県と長野県の間くらいにあるので、両方の県の特産品や郷土料理が並んでいました。いわゆる「田舎の郷土料理」というやつです。それらがじんわりと優しい味で、するすると食道を通り、すとんと胃に落ち着く。
食べ物を美味しいと感じたのが久しぶりすぎて、冗談抜きに涙が出そうでした。 この日の食事以降、私の食欲は徐々に快復していきます。宿の方々に、温泉と食事で生き返らせてくれて本当にありがとうございましたと言いたいです。
観光
万座温泉には温泉宿しかないっぽかったので、軽井沢まで戻ってバスで山の中へと向かいます。
記憶が曖昧なのですが30分くらい揺られて、白糸の滝へ行きました。
緑生い茂る山の中を澄んだ水がダバダバと流れる様が大好きで、帰りのバスを待ってる間しばらくぼーっと滝や川を眺めていました。
所感
軽井沢に別荘が欲しい。毎年行く。
箱根温泉 (神奈川県 足柄下郡 箱根町)
さて、万座温泉で温泉旅の良さを知ってしまった私は9月のシルバーウィークに2ヶ所の温泉へいきました。こちらはその前半部。
出身が神奈川県なので箱根温泉自体は何度か訪れていますが、箱根湯本より先には行ったことがなかったので、今回は強羅まで行ってきました。
ロマンスカー (懐かしい)
↓
箱根登山電車 (めっちゃ楽しい)
↓
箱根登山ケーブルカー (初めてみる)
と山に入っていくごとに乗り物が変わり、「そんなに箱根の山は傾斜がキツいのか…」と神奈川県出身のくせに驚くなどしました。
温泉
大涌谷が源泉の硫酸塩泉です。箱根で硫黄泉・硫酸塩泉の温泉を持つ宿がそもそもあんまりなく、かつ、私の貯金でも手が届く宿がこの桐谷箱根荘でした。
※ 箱根の温泉公式ガイド 箱ぴた で泉質から旅館検索ができるのでとても便利です。
宿にある温泉は以下の通りです (詳細は公式サイトを見てください)。
- 本館
- 内湯
- 露天 (男女入れ替え制)
- 家族用貸し切り風呂
- 別館1
- 内湯
- 露天
- 足湯 (宿泊でなくても無料で利用可)
- 別館2
- 有料貸し切り風呂
私の部屋は本館の内湯の目の前にあったので、夜は本館内湯、朝は本館露天へ行きました。さすがに万座ほどすぐにはすべすべにならなかったですが、それでもじっくりお湯に浸かっているうちにだんだんと肌がすべすべになっていきました。今回も朝の露天風呂は貸し切り状態で、ゆったりとできました (たぶん露天風呂の方が濃度が高かったです)。
観光
大涌谷
さきほどの箱根登山ケーブルカーを終点で降り、ロープウェーでさらに山奥を目指します。山奥というか、芦ノ湖ですね。芦ノ湖にはあんまり滞在しなかったのですが、ロープウェイから見える大涌谷は大迫力でした。
箱根の山
どこかのサイトに「90分くらいで辿れる」と書いてあったのでハイキング気分で箱根旧街道へ行きました。そしたらこれがもう大変な山登りで、「そういえば箱根の山は越えるの大変だったんだっけな…」と神奈川県出身者でなくても聞いたことがあるような知識を今更になって思い出すのでした。
所感
山篭りは楽しいが山登りは大変…!(次登るときがあったらちゃんと装備していこう)
平湯温泉 (岐阜県 高山市 奥飛騨温泉郷)
- 9/22 - 9/23 (一泊)
- 奥飛騨温泉郷 平湯 匠の宿 深山桜庵
- 単純温泉
シルバーウィーク温泉旅後半部です。奥飛騨!
ここを選んだのは、単純に山に囲まれたかったからというそれだけの理由です。ちょうど、某カードの優待で安く泊まれるようになっていたので選びました。
新幹線で松本まで行き、そこからバスで1時間半ほど行くといきなり温泉郷が現れます。それが平湯温泉です。
北アルプスを初めてみたのですが、本当に美しくかっこいいですね。後にブラタモリで「北アルプスは氷河が滑り落ちるとき一気に削ってできた山だから他の山より切り立った形をしている」とやっていていたく感激致しました。
温泉
とにかく宿が荘厳でした。こんなにいい宿とは予想しておらず、到着してからしばらく圧倒されていました。
温泉は内湯・露天・貸し切り風呂・貸し切り露天 (予約制) ・足湯 (出入り自由) がありました。夜は内湯とそこから繋がる露天、朝は貸し切りの露天風呂へ入りました。
なんて贅沢なのだ…!
宿のこと、特にお食事について
お風呂もですが、宿自体が本当に至れり尽くせりな宿で、食事は美味しいわ部屋は綺麗だわお土産は豊富だわ景色は最高だわ夜鳴きそばならぬ夜鳴きラーメンは出てくるわ…一泊じゃ足りない!
夕食にはとにかく飛騨牛がたくさん出てくる。最初から最後までずっと飛騨牛。飛騨牛本当に美味しくて、この宿から家へ配送もしたし、ふるさと納税でも送ってもらいました。
この頃にはすっかり元気になっていて食い意地も張っているので、深夜の夜鳴きラーメン食べようと思ってたのですが、さすがに食事をする気になれないほど満腹になりました。
そして朝ごはん。これが夕食の飛騨牛に引けを取らないくらいに美味しいです。優しい味。
観光
平湯温泉では地面のあちこちからお湯が湧き出ていて、こんな風に温泉たまごを作ってたり、無料の足湯がたくさんあったりします。
ここも温泉宿と商店以外ほぼ何もないと言っても過言ではないですが、山好きな私にはとても素敵な場所でした。やはりなんと言っても北アルプスの美しさ!惚れ惚れしてしまいます。
翌日のお昼頃に新穂高ロープウェイで展望台まで行ったのですがその時間は天気がよくなく、山には霧がかかっていたので何も見えませんでした…槍ヶ岳とか見たかった…
所感
美しい北アルプスと素敵な宿と美味しい飛騨牛。山籠りには最適。
鳴子温泉 (宮城県 大崎市 鳴子温泉)
- 11/23 - 11/26 (鳴子温泉一泊 / 仙台二泊)
- 鳴子温泉 湯元 吉祥
- 低張性アルカリ性高温泉(pH値8.6)
ずっと酸性泉質の温泉に行っていたので、アルカリ性の温泉にも入ってみたくなって鳴子温泉へ行きました。
新幹線で仙台の1つ先にある古川駅までいき、そこから JR 陸羽東線で約50分ほど揺られて鳴子温泉駅に到着です。
寒い…
ミネソタ州だのフィンランドだのに住んでいたので北国の気候には慣れていると思っていましたが、かなりの不意打ちを食らってしまいました。
温泉
内湯・露天・貸し切り風呂がありました。いつもの通り、夜は内湯とそこから続く露天風呂、朝は貸し切り風呂に入りました。
硫黄含有量が高い温泉だと湯あたりしやすくてあんまり長時間入れないのですが、ここの温泉は硫黄が入っていないのと低張性だからなのか、長時間気持ちよく入っていられました。
翌朝は雪が降っている中で檜風呂を貸し切り…大変風流で贅沢でした。
今回初めてのアルカリ性温泉だったので宿で成分のことを軽く調べたのですが、高校の頃化学が苦手で、受験のときは「これ終わったら全部忘れてやる…!」と泣きながらイオンだのベンゼンだのを覚えていったので、泉質について調べていてもよく分からないことが多くてもどかしかったです。。
観光
地獄谷
鳴子温泉からバスで30分くらい行ったところに鬼首地獄谷遊歩道があります。岩という岩、地面という地面からボコボコとお湯が湧き出していて、地球って活動してるんだなって壮大な気持ちになれるところです。とてもおすすめです。
下の2枚は鬼首間けつ泉にある、湯の滝です。
余談ですが間けつ泉が吹いたらプッシュ通知欲しいな…と寒い中待ってて思いました。
鳴子温泉付近
潟沼
宿からもっと山に入ったところにある潟沼。強酸性のため (pH2.4) 水の色が青緑色です。朝だったので雪が降ってて寒かったのですが、レストハウスのおじさん、おばさんがとても親切な方々で、温泉で淹れたというコーヒーは渋みと苦味がとても美味しかったです。
鳴子峡
紅葉シーズンが終わっていたのととても寒かったので全然人がいなかったです。遊歩道もオフシーズンだったり東日本大震災の影響で閉鎖されていたりで、歩くことはできませんでした。
ほんのちょっとですが、雪と紅葉という珍しい組み合わせを見ることができました。
仙台
鳴子温泉から陸羽東線で小牛田駅まで行き、そこから東北本線で仙台を目指します。 旅行では移動中に Google Map を開くのが好きなのですが、よくよく見ると日本三景の一つ、松島に停車することが分かりました。この日はよく晴れていたため予定を変更して松島へ。
15時の観光船最終便で1時間のクルーズを終えたらもう夕焼けになっていて、体感だと全然 JST じゃない…
仙台では友人に教えてもらったパンケーキカフェで江國香織の小説を読んだり、
宿の近くにある仙台市天文台に二度も足を運んでプラネタリウムを見たり、
市内からはちょっと遠いんですが仙台うみの杜水族館で美味しそうな鰯や鯖をみたりしました。
個人的には星が好きなので天文台はおすすめです。プラネタリウムもユーミンの歌を流してくれたりけっこうセンスのいい上映をやっていました。
所感
化学も地学も捨てちゃダメ。勉強しておくと後の人生楽しいよって高校生の自分に言いたい。
今後
温泉一人旅、最高すぎて来年もコンスタントにやっていきたいです。少しでも温泉地の助けになればいいなと思い、お世話になったところにはふるさと納税するようにしています。飛騨牛〜〜〜
山と温泉と美味しい食べ物が自分は好きなんだなと深く認識した一年でした。
Play Framework on IntelliJ
備忘録
仕様
仕様は上記の通り. 1. IntelliJ が Play に対応しているのは Ultimate 版のみ.お金を払いたくないので Student 会員になった. 1. Play 2.4.x は JDK 1.8 に対応しているが,IntelliJ 14 は JDK 1.7 推奨. 1. 現段階で IntelliJ の最新版は 15.15 (Ultimate) だと Play 2.4.6 で JDK 1.8 でいけるはず.
IntelliJ IDEA を使って Play Framework を使う
Play のドキュメントを見ると,2.3 までは IntelliJ IDEA から Play application を作成できたが,2.4.x では非推奨になっている.
- コマンドラインから
activator new NewProjectName
で新規プロジェクト作成 - IntelliJ IDEA 内で
Open
よりNewProjectName
を開く - sbt の設定画面が出てくるがとりあえず JDK のバージョンを揃えたくらいしかしていない
File ->
Project Structureを開き,
Projectと
SDKs` で JDK のバージョンを揃えるRun
->Edit Configuration
を開く.+
->SBT Task
で name は適当 (今回は Run),task をrun
として登録- Run コマンドが作られるので押すとサーバーが立ち上がる (今回はローカルの9000)
日本語ドキュメントを求めて Play 2.3.x のものを読むと死ぬ Document for Play 2.4.x:
ocaml-alab-mode もどきを作っているお話
この記事は 学生エンジニア Advent Calendar 2015 21日目の記事です.
この間このカレンダーを落とさないために今日の分のネタを投下してしまったので今日はおそらく一部の界隈にしか受け入れられないであろうお話をします (かなしい).
Agenda
- agda2-mode で TDD をした
- 上の経験により TDD 初学者の心を取り戻した
- OCaml ver. を作った
界隈の方にはふわっとしすぎたお話ですし,そうでない方にとっては聞き慣れない単語の羅列になっていると思います.頑張って動画とか載せてイメージしやすくしていくのでどうか諦めないでください…
agda2-mode
Agda というプログラミング言語がありまして,Coq を知っている方は聞いたことあるかなと思うのですが,定理証明をするための言語です.Coq との違いはここでは触れませんが,Coq よりも プログラミングしているっぽい 感覚で定理証明をすることができます.Haskell を書いたことがある人は,あれに依存型が入ったような感じと思っていただければ.そう,依存型.Dependent Type.
一言でいうと (たぶん怒られそうなのですが) 「型に依存した定義を持つ型」というわけです.依存型の説明でおそらく一番有名なのは「安全な head 関数を作る」だと思います.@yoshihiro503 さんのこのブログなど分かりやすいです (これは Coq ですが).
分からなくても大丈夫です.今回は依存型の話はしません.できません.とりあえずおそらく皆さんが普段イメージする「型」の概念よりももう数段神様の世界に近づく概念だと思ってください.
で,この Agda の授業が大学院の授業であったんですね (講義録).
このとき私は Agda を書いていたというよりも agda-mode (agda2-mode) というものに Agda を書かされていたわけです.
これは Emacs のモードの一つで,Agda を書いているときにプログラム中に expression として ?
(hole) を書くことができ,その部分の型とそのときの型環境を表示してくれるものです.あと hole 内に書いた変数で case
式 (pattern match) とかを展開してくれます.とにかく agda2-mode が言った通りの型 (の値) を型環境にあるものを使ってうまく作って hole に入れてあげればいいわけです.
言っても分からないと思うので見てください.下のウィンドウに hole の型が表示されています.今回コマンドを押し忘れたのですが,hole のところで C-c C-,
とすると hole の型だけでなくスコープ内にある変数の型一覧 (型環境) も表示してくれます.
超便利!!型合わせゲーム最高!!!TDD (Type Driven Development)!!!TDD (Type Driven Development)!!!
ちなみになんと最近流行りのモダンなエディタ Atom にもこの agda-mode があるので宗教上の理由により Emacs を使えない方はこちらをお試しください.
実際に使ってみた私のらぼの同期の記事はこちら
プログラミング初学者の心
当時私は大学の後輩になんとか OCaml の可愛さを理解していただきたく,先輩が実装された型デバッガというものを初学者向けに改良する,ということをしていました.この型デバッガはコンパイラの型推論器を使ってプログラム中の型エラーの原因を特定していくデバッガなのですが,対話的である という点が画期的なところ (の1つ) です.型デバッガはユーザに,例えば「ハイライト部分にある変数 x
の型を int
だと意図しているか?」と (n >= 1 回以上) 尋ねます.ユーザはこの問いに対して yes, no で回答していくだけでどこで型 (推論) が conflict しているのかを見つけ出すことができます.要するに,コンパイラが推論した型とユーザが意図している型がどこで食い違っているかを探索していく,というものです.
こちらも百聞は一見に如かずです.以下では見かけは同じ2つのプログラムの型エラーの原因が,ユーザが意図している型によって異なる例です. (ちなみに以下では OCaml 3.12 になっていますが 4.01 まで対応しています)
おかげ様で型デバッガを採用した OCaml の授業を受けた学年は「C より Java より OCaml が好き」と言ってくれるまでに OCaml を愛してくれました.めでたしめでたし……
というわけにもいかなかったのです.
弊大学の OCaml の授業では TDD (言わずもがな T は Type の T) を最初から導入していて,関数を書く前にコメントアウトでその関数の型を書かせるようにしています.例えば「リストの中の整数全てに与えられた整数 p を足したリストを返す関数 plus_p」なら
(* plus_p: int list -> int -> int list *)
というのが全体像となります.これを考えさせてから実際に plus_p
本体の実装をするようにしています.これを考えるとき,自然とアルゴリズムや他の関数のことやモジュールの設計なんかについてなんとなーく考えるようになりますから.それからこれがしっかり書いてあると他の人が読みやすいのです.なんていったって型はドキュメントですので.
型はドキュメント
— ゆずこ@這いよるお嬢様 (@yuzumikan15) 2015, 8月 17
…でもさっきのあれ,コメントアウトなんですよね.
だから適当なこと書く人も割といて,最初に全体像を把握出来ていない,ドキュメントを考えられていないからプログラムの中身をどう書いていいのか分からない,そんな """負 (不)""" があったわけです.
前置きが長くなりましたが,そんなわけでさっきの agda2-mode の OCaml ver. を作ろうと,そう,思ったのです.
ocaml-alab-mode
名付け親は私です.alab
は弊研究室がこの界隈では「A研」で通っていて,弊大学の OCaml の授業で使う OCaml のサブセットについては網羅していこう,というところから alab-mode
となりました.あと現段階では Emacs でしか使えません.agda-mode for Atom が悔しかったので時間できたら Atom 用のパッケージでも作ります.Vim 用は Vimmer のどなたかにお任せ致します (びむすくりぷと…).
ソースコード
yuzumikan15/ocaml-alab-mode · GitHub
なんかいろいろ入っていますが dev branch の
- OCamlMakefile
- Makefile
- main.ml
- my_compile.ml
- expander.ml
- printtypes.ml
- hole.el
があればいいと思います.あと README の Requirements にあるものたち.
全然リファクタリングしてなくてとっ散らかったプログラムなので本当に全方位平謝りです.まさかり投げないでくださいごめんなさい…
型注釈を付ける
今回 alab-mode を実装するために,ユーザが書いているプログラムを OCaml のコンパイラに渡して型付きの抽象構文木 (Typedtree) を作ってもらい,それを walk することで hole や環境の型を求めています.なので expression をいきなり hole にしてしまうと全てが多相になってしまいます.何を言っているか分からない人はとりあえずこれだけ覚えてください.
ソースコードには型の annotation を付けて!
(* plus_p: int list -> int -> int list *) let plus_p lst p = List.map (fun x -> x + p) lst
というコードは
(* plus_p: int list -> int -> int list *) let plus_p (lst: int list) (p: int): int list = List.map (fun x -> x + p) lst
か
(* plus_p: int list -> int -> int list *) let plus_p: int list -> int -> int list = fun lst p -> List.map (fun x -> x + p) lst
という形で型注釈を付けることができます.でないと今デバッグ用のエラーメッセージ出てきてしまいますから!!お願いします!!!
機能
- hole の挿入,削除
- hole の展開 (expression 指定なし): tuple, record のみ
- hole の展開 (expression 指定あり)
- 指定した変数での
match
式の挿入: list, option, ユーザが定義した型 (record, variant) のみ if
式の挿入
key bind は README にある通りです.
hole の挿入,削除
agda2-mode では ?
が書けるようになっていましたが alab-mode では C-c h
で入ります.いきなりハイライトされていますが内部的には (exit(*{}*n))
(n は自然数) となっています.なので alab-mode では exit n
が使えないのですね…
hole の展開 (expression 指定なし)
agda2-mode の hole に何も書かないときの refine と同じことをしています.
(* make_pair: 2つの整数をもらい2つ組を返す *) (* make_pair: int -> int -> int * int *) let make_pair: int -> int -> int * int = fun p q -> (p, q)
を書きたいときに最後の expression を C-c h
で hole にしてあげて (以下のようになります)
(* make_pair: int -> int -> int * int *) let make_pair: int -> int -> int * int = fun p q -> {}0
0番の hole のところにカーソルを合わせて C-c r
とすると
(* make_pair: int -> int -> int * int *) let make_pair: int -> int -> int * int = fun p q -> ({}0, {}1)
みたいに勝手に2つ組の形に展開してくれるような機能です.tuple と record に対応しています.
tuple の例.2つ整数をもらってきて2つ組を作ります.
hole の展開 (expression 指定あり)
hole に expression を書いた状態で refine をします.このとき expression を入れた状態でコンパイラがエラーを出さなかったら refine でき,何かしらのエラーメッセージが出たら refine できないようになっています.
person
型が先に type
で定義されていて,make_person
ではこの person
を作ります.以下では最初に0番目の hole に型の違う変数 age
を入れると下のウィンドウにエラーメッセージが出てきて refine できません.
match 式, if 式の挿入
hole に書いた変数で pattern match をすることができます.現段階では tuple, list, option, ユーザが定義した (同一ファイル内の) 型 (record, variant) に対応しています.
また,hole のところで C-c i
とすると if 式を挿入できます.
実際に使ってみる
目標は弊大学の OCaml の授業でまともに使えるようにすることなので,この授業の課題を1つ解いてみましょう.
八百屋木(「文字列(野菜名)と整数(値段)のペア」の木)と 野菜リスト(文字列(野菜名)のリスト)を受け取ったら、 野菜リストの中にある全ての野菜を買えた場合のみ、その代金の合計を返し、 野菜リストの中にひとつでも八百屋に置いていない野菜があった場合は 0 を 返すような 関数 total_price をデザインレシピに従って作れ。
一般的な木の型として以下が与えられているものとします.ちなみに二分探索木とします.
type ('a, 'b) tree_t = Empty | Node of ('a, 'b) tree_t * 'a * 'b * ('a, 'b) tree_t
'a
, 'b
は型変数なので,この課題の八百屋木は (string, int) tree_t
となります.
issue
github の issue の通りですが目下の課題は
- next goal, previous goal の key bind による移動
- 任意の型 (を持つ変数) について pattern match (現在決め打ちで出力している list, option などの OCaml が定義している型は,本当はそこまで探索できるようにしたい)
- ocaml-alab-mode を minor mode にする
です.あとなんか無駄に改行が入るのと,pattern match したときのコンストラクタの引数名どうにかしたいですね……
まともに使えるようになったら来年度の OCaml の授業はこれと,型デバッガと,あともう一つ秘密兵器を使えるようになります (論文とかの関係で言っていいのか分からないので伏せておきます…).みんな頑張ってください.
Nearby Messages by Swift
この記事は 学生エンジニア Advent Calendar 2015 17日目の記事です.
こんにちは.
一昨日引越しして荷解きと収納が嫌になったので普段は書かないブログを積極的に書いていこうと思います.
今日は Google の Nearby Messages API についてです.
この API は今年の Google Play Services 7.8 リリースの際に追加された Nearby API の中の1つで, 音を使って他の端末と情報共有をするための API です.iOS 版はまだ β版らしいですが iOS 7.0 以降で使えるみたいです.
Nearby には今回紹介する Nearby Messages API と Nearby Connections API があります.Messages は文字通り複数の端末とメッセージを共有するために,Connections はこちらも文字通り複数の端末に接続するために用いられます.Nearby API を使うときは端末の Wi-Fi, Bluetooth 共にオンである必要があります.
既に試してみたというブログや,この API を使った Android アプリの紹介があったりするのでそちらもどうぞ.
Android - Nearby Messages APIでチャットみたいなのを作ってみる - Qiita
Nearby Message API を試してみた - 質量
Nearby API であなたを取り巻く世界とつながる - Google Developer Japan Blog
さて,これらは全て Android の記事ですので,今回は iOS で試してみたいと思います.というか,以前ハッカソンで初めて使ったのでそのときのことを書きます.
(雑な記事です.紹介したブログのような親切さは欠片ほどもありませんので予めご了承ください)
API の有効化
こちらはほぼ Android と同じ手順です.Android 版は先ほど紹介した記事にもありますし,iOS 版は英語だったら公式に載っているので読んでください.
ざっくり日本語で説明すると,
- 最新の Xcode をインストール (6.3 以降なら OK っぽいです)
- CocoaPods をインストール
- Nearby API を CocoaPods で入れる
- Google アカウント作成
- API Key の取得
- プログラム中で message manager object を作成
となります.
1, 2 の Xcode や CocoaPods, 3 の pod install
あたりは iOS 開発者なら問題ないと思います.また,4 の Google アカウント作成もだいたいの方は既に (いくつか …???) 持っていらっしゃると思います.(ちなみに今流行りの Carthage にも入っているかは分からないです.知見共有お願い致します)
5 以降,Google Developers Console を使って API を有効化します. 公式に書いてあるそのままですが,
という手順を踏みます.
各項目の細かな手順は公式に書いてありますし,割と親切な GUI なので迷うことはないと思います.Google Developers Console を初めて使った私ですら大丈夫でしたので…
iOS ↔ Android
ハッカソンで使ったときは私が iOS, もう一人のエンジニアが Android 担当で Nearby Messages を使って情報をやり取りしていました. 公式の手順5の下に ★ Note とあるように,iOS, Android 両方使いたいときは,(a) で同じプロジェクトを使ってください.当時は Android 側で作ったプロジェクトに iOS の project name と bundle identifier を追加して API Key をもらっていたような気がします.
Bridging-Header
公式通り Objective-C で書いている方はここは飛ばしてください.Swift で書いている方は,Nearby API が Objective-C なので Bridging-Header を作ります (Bridging-Header を作ったことがある方もここは飛ばしてくださって大丈夫です).
YourProjectName-Briding-Header.h に
#ifndef YourProjectName_Bridging_Header_h #define YourProjectName_Bridging_Header_h #import <GNSMessages.h> #endif
を書いて,
- TARGETS
- Swift Compiler - Code Generation
- Install Objective-C Compatibility Header -> Yes
- Objective-C Bridging Header -> Path to your bridging header
- Swift Compiler - Code Generation
を設定します.
Create Message Manager Object
手順 6 でようやっとプログラムに何か書きます.Message Manager Object (GNSMessageManager) の初期化です.Message Manager Object は Publication, Subscription を管理するためのクラスです.たぶんどこで初期化してもよいのですが,ハッカソン時はアプリ起動時から pub / sub を行いたかったので AppDelegete.swift 内に書きました (本当は Nearby Messages 用のクラスを別に作って AppDelegate 内でインスタンス作るとかの方がよいのでしょうけど,ハッカソンなので設計などは許してください).
具体的には
let nearbyAPIKey = "Your Nearby API Key" var messageManager: GNSMessageManager? func initMessageManager () { messageManager = GNSMessageManager(APIKey: nearbyAPIKey) }
でいいと思います.思います,というのは,私のソースコードにはそう書いてないからです.公式もそうなっていますが,今後,マイク使用の許可,Wi-Fi や Bluetooth がオンになっているかなどのトラッキングをするのでここはもうちょっと膨らみます (なので最初から initMessageManager を作っておきました).
アプリの初回起動でこんなダイアログがでてきて,Nearby API を使うのに必要なマイク,Wi-Fi,Bluetooth の使用許可を求めてきます.
ちなみに messageManager
は Optional にしていますが,今流行りの - [要出典] lazy var
でもいけるんじゃないでしょうか.var
+ !
?? 知らない子ですね.
Pub / Sub
いよいよメッセージの送信,受信をしてみましょう.
ユーザ設定と Permission のトラッキング
その前に,先ほど書いたユーザへの Nearby API 使用のための様々な許可 etc. のトラッキングを設定していきます.
ユーザ設定のトラッキング
公式 だと 'Tracking user settings that affect Nearby' という部分をやります.先ほどの initMessageManager
では マイク,Wi-Fi,Bluetooth 使用の Permission 確認ダイアログが出てきただけでした.ここでユーザがこれらの使用を許可しなかったり,Bluetooth がオフになっているときにアラート (アラートじゃなくてもいいのですけど) を表示してユーザに Nearby API が使えないことを知らせることができます.次のサンプルではとりあえず print
しているだけです.適宜,何かしらの UI を作ってください.
func initMessageManeger () { messageManager = GNSMessageManager(APIKey: nearbyAPIKey) { (params: GNSMessageManagerParams!) -> Void in // This is called when microphone permission is enabled or disabled by the user. params.microphonePermissionErrorHandler = { hasError in if (hasError) { print("Nearby works better if microphone use is allowed") } } // This is called when Bluetooth permission is enabled or disabled by the user. params.bluetoothPermissionErrorHandler = { hasError in if (hasError) { print("Nearby works better if Bluetooth use is allowed") } } // This is called when Bluetooth is powered on or off by the user. params.bluetoothPowerErrorHandler = { hasError in if (hasError) { print("Nearby works better if Bluetooth is turned on") } } } }
ちなみにこれは
GNSMessageManager(APIKey: nearbyAPIKey, paramsBlock: { (params: GNSMessageManagerParams!) -> Void in ... ... })
の Trailing Closure です.でもここまで長いと Handler を別に定義してあげるのがよさそうですね…あと抽象化したい…
Permission のトラッキング
公式 の 'Tracking the Nearby permission state' のところです.ユーザが Nearby API の使用を許可した / しなかったときに何かしらのアクションを起こすことができます.Permission Tracking には GNSPermission
というクラスを使います.GNSPermission.isGranted()
で 許可したかどうかを取ってくることができ,GNSPermission.setGranted (granted: Bool)
で permission を set します.
次のサンプルは,画面の左上にボタンを作り (i.e. ツールバーの left button),ボタンを押すことで Nearby を許可したりしなかったりを切り替えるものです.
var nearbyPermission: GNSPermission? // messageViewController: ツールバーを設置する画面 (ViewContoller) func setupNearbyPermission () { let changedHandler: Bool -> Void = { [unowned self] granted in let answer = String(format: "%@ Nearby", granted ? "Deny" : "Allow") self.messageViewController.leftBarButton = UIBarButtonItem(title: answer, style: UIBarButtonItemStyle.Plain, target: self, action: "toggleNearbyPermission") } nearbyPermission = GNSPermission(changedHandler: changedHandler) } // Toggles the permission state of Nearby. func toggleNearbyPermission() { GNSPermission.setGranted(!GNSPermission.isGranted()) }
公式にも注意書きがありますが,ユーザの意図に反して permission を set しないでくださいね.
Publication
長かった…ここまで本当に長かったです…ブログ書くのって本当に体力使いますよね……
公式だと Publishing a message のところです.
GNSMessageManager
のインスタンスの messageManager
に送りたいメッセージを入れて GNSPublication
クラスのインスタンス (以下では publication
) に渡してあげます.
publication
が nil
ではない間ずっとメッセージは送信し続けられます.逆に,publication
を nil
にすると送信は止まります.以下はメッセージとして JSON を送るようにしています (公式ではメールアドレスですね).ちなみに JSON を扱うのに SwiftyJSON を使っています.
var publication: GNSPublication? func startPublication () { if let mgr = self.messageManager { let json = JSON(someDictionary) do { // JSON.rawData() が exception を出すようになっているので try します let message = GNSMessage(content: try json.rawData()) // ここで publication にメッセージが入った時点で publish が開始される publication = mgr.publicationWithMessage(message) } catch { // 本来はちゃんとなんらかの対処をしてあげてください print("json.rawData() throwed an exception") } } else { // 本来は (ry print("messageManager is nil") } } func stopPublication () { publication = nil }
Subscription
次はメッセージの受信です.
こちらも Publication のときと同様,messageManager
でハンドラなどを設定して GNSSubscription
クラスのインスタンス (以下では subscription
) に渡してあげます.subscription
も nil
ではない間ずっと受信できるよう待機しています.
受信する際,subscript
にはなんらかのメッセージを受信した際に呼ばれるハンドラと,メッセージを失ったときに呼ばれるハンドラの2つの GNSMessageFoundHandler
が渡されます.
func startSubscript () { let messageFoundHandler = { [unowned self] (message: GNSMessage!) in let messageStr = String(data: message.content, encoding: NSUTF8StringEncoding) if let data = messageStr?.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) { let content = JSON(data: data) ... ... } else { // 本来は (ry print("data is nil") } } let messageLostHandler = { [unowned self](message: GNSMessage!) in if let content = String(data: message.content, encoding: NSUTF8StringEncoding) { // 本来は (ry print("Lost message: \(content)") } else { // 本来は (ry print("cannot convert message.content to String") } } subscription = messageManager.subscriptionWithMessageFoundHandler(messageFoundHandler, messageLostHandler: messageLostHandler) } func stopSubscription () { subscription = nil }
使ってみて
ハッカソンのときは私ももう一人も Nearby を使うのは初めてでしたが割とすんなり使えて,しかもちょっと大きめの JSON をやり取りすることができたので,今後なにかをサクッと共有したいときには使っていけるなぁと思いました.ちょっと新しい技術使ってる感があって (あとこなしちゃん -後述 がいたのもあって) ハッカソンはとても楽しかったです.
ちょっとよく分かってないのですが,GNSPublication
や GNSSubscription
が nil
になると送受信が止まるというのはどうなんでしょうね?
公式の Android 版 をみると
@Override protected void onStop() { if (mGoogleApiClient.isConnected()) { // Clean up when the user leaves the activity. Nearby.Messages.unpublish(mGoogleApiClient, mMessage) .setResultCallback(new ErrorCheckingCallback("unpublish()")); Nearby.Messages.unsubscribe(mGoogleApiClient, mMessageListener) .setResultCallback(new ErrorCheckingCallback("unsubscribe()")); } mGoogleApiClient.disconnect(); super.onStop(); }
こんな感じで unpublish
なるものが存在していて,こちらのほうがよいのではないかなと思うのです (というか Android 版めっちゃ親切にいろいろ書いてありますね…!!).
(GNSPublication
や GNSSubscription
のインスタンスは GNSMessageManager
から設定を渡されるとき以外出てくることはないので,そのうち意図的にではなく implicit に nil
になってしまうこととか…ないですかね… GC 的な…ない?)
ソースコード
あるけどまだどこにも載せてないですすみません. ハッカソンのときは受信したメッセージを元に Konashi にコマンドを送ったりしていたので今回のお話にはちょっと余計なコードが入っているのと,ちょっと汚かったのでリファクタリングしてたのですがよく考えたら端末を1台しか持っていなくて動作確認ができない,というのが理由です.本当にすみません.(Android 用のも書いて動作確認してみるかなぁ…)
次回は kmd_09 さんです.
セルゲイ・ラフマニノフ 前奏曲嬰ハ短調 Op.3-2 (鐘)
この記事はクラシック曲 Advent Calendar 2015 8日目の記事です.
5歳の頃から高校までピアノを弾いていました.クラシックはショパンのノクターンから入り,今回紹介するラフマニノフの鐘が,おそらく最後の発表会で弾いたクラシック曲です.浅田真央選手が使っていたので知っている方も多いでしょう.
曲を聴く前に,皆さんは「鐘の音」と聞くとどんな音を思い浮かべますか?
私が譜面も作者も知らないときにタイトルだけからイメージしたのは,お寺の鐘の音でした…除夜の鐘みたいな……日本人ですからね…
先生から譜をもらってとりあえず弾いてみるとなんとも暗い.遅い.そうかと思うと突然慌ただしくなる.全然イメージがわかなくて CD ショップ行って様々なピアニストの鐘を試聴しました.でも本当になんでこの曲が鐘なのか,どこが鐘なのか分からなかったです.
慌ただしいところ以外はテンポも遅く,複雑な音符もないので,練習するモチベーションがあんまりなかったのですが,そんな中でもいろいろ試聴はしていて,あるときついに,ワイセンベルクの鐘を聴いたとき,きました,鐘の音.
ロシアの教会だ!ロシアの,モスクワあたりの古い教会の鐘の音だ!モスクワはおろかロシアなんて行ったことないけどこれはロシアだ!って思いました (よく考えたらラフマニノフはロシア人だしこの曲はモスクワでお披露目されたのでそりゃそうだろうという感じなのですが). ロシアだしきっと冬はめっちゃ寒い.寒くてとても暗い,空気も重いんだろう.外に出る人なんて全然いない中で教会の鐘が重厚な音を響かせている,そんなイメージが完全にできあがりました.
2'39'' からのラストは低音部の重厚な和音と高音部のかっちりとした音がどちらも同じくらいの音の大きさ (譜は忘れましたが fff くらい?) で交互に出てきて,いかにもゆっくりと左右に揺れて音を出す鐘って感じがするのはよい.そこはどのピアニストもそうでした. ワイセンベルクが他と違ったのは,最初の方や,一番最後の小さな和音でさえも金属音のようなカチッとした音で弾いてるところです.最初から最後までずっと鐘の音でした.除夜の鐘なんて想像して本当に申し訳ない限りです.
そんなこんなでこの曲は私にとって思い出深い曲の1つとなりました.大学に入ってフィンランドへ留学したついでにヨーロッパをちらほらとまわってきたのですが,どの町へ行ってもとにかくまず教会へ足を運びました.今でも冬になって風が身にしみるようになると必ず聴きたくなります.
でも実はまだロシアに入ったことがないのです…いつか真冬のモスクワに行きたいなーとは思ってるのですが…
最後に,ラフマニノフ自身が演奏しているものを.
明日は Ptu_ さんです.