電子ピアノを買った

KORG の LP-380 という電子ピアノを 7/2 に購入して 7/4 の朝に届き、夕方組み立てました。

www.korg.com

僕の家族とピアノについてのありふれた話を唐突にしたいと思います。母親は幼少期にピアノを習っていてアップライトピアノを買い与えられ(それが今でも僕の実家に置かれている)、妹もヤマハ音楽教室に通ってぷらいまりーから始まり家でブルグミュラーを練習したり中学・高校生の頃は華麗なる大円舞曲とか幻想即興曲らへん(記憶が曖昧)を発表会に向けて練習していたり、夜遅くの練習のためにペラペラのキーボードが1台あった、そういう感じの環境でした。

実家のマンションでは他の家でも女の子のいる家庭からは同じような曲を練習している音がよく聞こえてきていたので、僕の実家も当時のよくある家庭の形の一つだったのかもしれません。

対して僕はピアノのレッスンをほぼ受けたことがないのですが(幼稚園の頃1年間だけヤマハ音楽教室に通っていたが事情がありやめてしまった)、上記のような感じで鍵盤を弾いて音が鳴る環境が家にあったので気になった曲の耳コピをして遊んだり、大学でジャズサークルに一瞬だけ入った影響でコードの読み方とかいろんなスケールの存在をなんとなく知って、それで巷で流れる音楽で気になったやつのコード譜をインターネットで検索して見ながら押さえてみたりとか、そういうおもちゃみたいなピアノの触り方をしていました。

実家を出てからはピアノに触る機会は無くなり、他に優先して買うべき家具があったり、やりたいことが諸々あったり(僕は一度に複数の対象に注意を払うことがマジの苦手なのでそれらを順番に向き合っていくしかない)、そもそも家に置くスペースが無かったりといった理由によってピアノは買わなかったのですが、やっぱり気になった曲があったら鍵盤を押さえて音を取ったりコードを確かめたりしたいよなあとはずっと思っていて(なんじゃその用途って感じやが)、というかピアノを習っていた人なら誰でもやってるブルグミュラーってやつを僕も真面目に練習してみたいなという思いもあり、やっぱり電子ピアノが欲しいなあ(仕事が終わってから夜でもヘッドホンをつけて弾けるので)という思いが常に頭の片隅にあったのですね……

それで最近は五十嵐先生の「プログラミング言語の基礎概念」という本を読み終えて(めちゃめちゃ良い本でした)次にあの有名な「型システム入門」を読み始めたのですが、これは非常に分厚い本なので読み切るにはそれなりの時間がかかります。すると一つの対象について関心を持っている期間はそれ一つに向かって視野が非常に狭くなる傾向があるさすがの僕でもこれはある程度長い目で接していくべき本であるなと気が付きました。

そこで脳と気持ちに余裕が生まれたので最近ついに新しく棚を買って部屋を整理してスペースを作り出し、電子ピアノを様々探してこれにしようと決めて購入しました。

Amazon のレビューを見ていると、いつやめるかわからない娘のレッスンのためならこのくらいお手頃な機種で十分、というようなことも書かれていましたが、さっきちょっと実際に触ってみた限りでは僕はこの LP-380 という機種でも一生かかってもその表現の幅を使い切れないだろうと思ったのでまあ久しぶりに大きな良い買い物ができたなと思いました。そういうわけで今けっこう嬉しいです。

Auth0 入門

Auth0

Auth0 はアプリケーションのログイン・ログアウトやID管理といった認証システムを提供してくれるサービス。 認証部分のコーディングやセキュリティ周りの構築を丸投げできて便利。

無料プランでも7000アクティブユーザまで管理できて "Up to 2 social identity providers" 1 なので趣味で使うには十分かと思う。

テナント

Auth0 のアカウントを作成するとまずテナントと呼ばれるものを作ることを求められる。 テナントは各種 identity provider があなたのアプリの URL (の代わり)として認識するもので、要は各種 identity provider と実際のアプリとの間に入る抽象。 YOUR-TENANT-NAME.us.auth0.com みたいな名前で Auth0 全体でユニークである必要がある(たぶん)。

最初は pione30.us.auth0.com というテナント名にしてみたけど、後からドキュメント を読んでみると

You can create more than one tenant; in fact you are encouraged to do so for each environment you may have, such as development, staging, or production.

とあるので、なるべく粒度を細かくテナントを分けるのがベストプラクティスなのかなという感じがする。例えば awesomeapp-staging-pione30.us.auth0.com みたいな。

テナントを作成したら Quickstarts を読みながら自分の作りたいアプリに合った導入ガイドに従うと良い。例えば React で SPA 構築するぞという場合はこちら

コネクション

ユーザが入力するログイン情報の提供元と Auth0 との関連はコネクションと呼ばれる。

自分のアプリが使うように設定したコネクションは実際にはユーザの目に触れる「ログイン情報を入力してください」画面でユーザが選択可能なログイン手段として表示されることになる。 例えばユーザ名・パスワードによるログインはDatabase Connectionsと呼ばれている。

ソーシャルアカウントを使ったログインが主流[要出典]な現代、ご多分に漏れず Auth0 でも様々な Social Identity Providers が利用可能である(一覧はこちら)。

例えば「Twitter アカウントでログイン」機能をユーザに提供したいと思ったらこちらのドキュメントを読みながら設定していきましょう。事前にTwitter Developer accountの申請が必要です。

おわりに

便利な世の中です。情報を整理してまた何か追記するかも。

失敗する可能性があるfoldをtry_foldで楽に書く

std::iter::Iterator::fold という便利なメソッドがあります:

let vec = vec![1, 2, 3];

let sum = vec.iter().fold(0, |acc, x| acc + x);

assert_eq!(sum, 6);

いま、 fold に渡すクロージャ内の処理で失敗する可能性があり、 ? 演算子を使いたくなったとします。どのように書けば良いでしょうか?

fold の型は

fn fold<B, F>(self, init: B, f: F) -> B
where
    F: FnMut(B, Self::Item) -> B,

であり、 ? 演算子を使うために f の戻り値型(つまり B)は Result 型である必要があるので、初期値 initResult 型になり、例えば以下のようなコードを書くことになります:

fn parse_sum(vec: Vec<String>) -> Result<u64, std::num::ParseIntError> {
    vec.iter().fold(Ok(0), |wrapped_acc, string| {
        wrapped_acc.and_then(|acc| Ok(acc + string.parse::<u64>()?))
    })
}

fn main() {
    let vec = vec!["1".into(), "2".into(), "3".into()];

    let res = parse_sum(vec);

    assert_eq!(res.unwrap(), 6);
}

ところで ? 演算子はエラー時にその直近の関数(またはクロージャからしか脱出せず、 上記のコードで parse 時にエラーが発生したとしても foldイテレーションは止まりません:

fn parse_sum(vec: Vec<String>)V -> Result<u64, std::num::ParseIntError> {
    vec.iter()
        .inspect(|string| println!("passing {} to fold", string))
        .fold(Ok(0), |wrapped_acc, string| {
            wrapped_acc.and_then(|acc| Ok(acc + string.parse::<u64>()?))
        })
}

fn main() {
    let vec = vec!["1".into(), "2".into(), "hello".into(), "3".into()];

    let res = parse_sum(vec);

    assert!(res.is_err());
}
passing 1 to fold
passing 2 to fold
passing hello to fold
passing 3 to fold

できればエラーが発生したらその時点で早期にエラーを返してほしいですね。

そんなときに try_fold が便利に使えます。

try_fold の型は以下のようになっています:

fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
    F: FnMut(B, Self::Item) -> R,
    R: Try<Ok = B>,

さきほどの例は、初期値を Ok でラップしたり and_then を使ったりすることなく以下のように書き直せます:

fn parse_sum(vec: Vec<String>) -> Result<u64, std::num::ParseIntError> {
    vec.iter()
        .try_fold(0, |acc, string| Ok(acc + string.parse::<u64>()?))
}

fn main() {
    let vec = vec!["1".into(), "2".into(), "3".into()];

    let res = parse_sum(vec);

    assert_eq!(res.unwrap(), 6);
}

さらに try_foldクロージャがエラーを返した時点でただちにそのエラーを返します:

fn parse_sum(vec: Vec<String>) -> Result<u64, std::num::ParseIntError> {
    vec.iter()
        .inspect(|string| println!("passing {} to try_fold", string))
        .try_fold(0, |acc, string| Ok(acc + string.parse::<u64>()?))
}

fn main() {
    let vec = vec!["1".into(), "2".into(), "hello".into(), "3".into()];

    let res = parse_sum(vec);

    assert!(res.is_err());
}
passing 1 to try_fold
passing 2 to try_fold
passing hello to try_fold

便利ですね。

普段 fold だけに目が行きがちなので書いてみました。