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

株式会社ラブグラフを退職しました

4月21日を以て株式会社ラブグラフを退職した.最後のわがままで,今まで使ったことのない有給休暇を消化させてもらえることになったので,5月半ばまでは在籍することになっているが,ともかく今日が最終出社日だった.2015年3月頃から手伝っていたので,およそ2年に渡って関わり続けてきたことになる.長い間,様々な人たちから「やめろやめろ」と言われていながら,ようやく退職を決意することにしたわけであるが,以下に主たる理由を3つ挙げる.

続きを読む

curl の -b, -c (--cookie, --cookie-jar) オプションが便利

体系だった大掛かりな記事を書こうとすると,なかなか気力と労力が必要で,結局書き上がった頃には多大なる時間を費やしているということがままあるので,もう少し雑にお役立ち情報を書いていきたい.そこで,TIL (Today I Learned) を (GitHub に push するのではなく) 記事にしていこうと思う.

既に today ではないのだが,先週末に curl について便利なオプションを知ったのでまとめておく.curlcookie を送受信する際には -b / --cookie -c / --cookie-jar という便利なコマンドがあるのでこれが使えるという話.

続きを読む

Cycle.js を JSX で書く

Cycle.js と DOMDriver で Web アプリケーションを書くとき,sink に流す仮想 DOM を JSX で記述したい.公式を読むと普通にやり方が書いてあったが,ググって解決しようとしていると,古い手順に当たってしまい,少し引っかかってしまった.加えて,「最近のフロントエンドのエコシステムはこういう感じなのか」と思うところもあったので,同じような立場の人のために記録を残しておくことにする.なお,同じ轍を踏まぬよう,読者諸賢におかれましては,あくまで2017年1月30日現在の情報であることにご注意願いたい.

以下では,Cycle.js (w/ xstream) でウェブアプリケーションを構築する.また,アセットのビルドには webpack を用い,babel-loader を通じて,ES2015+ および JSX のトランスパイルを行うこととする.

なお,今回のプロジェクトは GItHub 上で公開しているので,参考にしていただきたい.

github.com

続きを読む

Vim script でジェネレータを作ったり、遅延評価してみる

この記事は CAMPHOR- Advent Calendar 2016 8日目の記事です.

はじめに

日本時間の2016年9月12日に,Vim 8.0 がリリースされた.Vim 7.4 のリリースからはおよそ3年振り,Vim 7.0 からは実におよそ10年振りのバージョンアップだそうだ.Vim 8.0 では様々な新機能が追加されたが,中でも Vim script にラムダ式が追加されたのには目を引くものがあった.

ラムダ式の登場により,標準の map() 関数や filter() 関数の使い勝手が改善されたが,これらで遊んでいるうちに,似た操作をリストだけではなくイテレータに対して適用したいという欲求が自然と生まれてきた.しかしながら,Vim script にはリストはあれど,イテレータなどというものは存在するはずもないので,今回自分で実装する運びとなった.

本稿では,まず初めに,ECMAScript 2015 のインターフェースに似た*1,すなわち,next を呼ぶと { value: 42, done: false } という形式に近い値が返ってくるイテレータVim script で実装する.次に,このイテレータを返す関数,すなわちジェネレータを定義する.その後,イテレータを拡張し,mapfilter などのよく知られたメソッドを定義することで,種々の操作を簡便に行えるようにする.

これまでの流れ

*1:あくまで似ているだけで,互換ではない.特に,next メソッドが引数を受け取ることを想定しない.

続きを読む

Rust の turbofish と GHC 8 の Type Application ― または我々は如何にして多相な関数を単相化するか

Rust には std::str::FromStr という trait があって,データ型がこれを実装すると,from_str という名前の associated function *1 を通じて,str からそのデータ型に変換できるようになる.

use std::str::FromStr;

fn main() {
    let x = i32::from_str("42");
    println!("{}", x.unwrap()) // 42
}

これだけ見れば,特に取り立てて議論するべき点はない.

一方.strparse というメソッドを持っていて,文字通り文字列のパーズを行うのだが,以下のようなシグネチャをしている.

fn parse<F>(&self) -> Result<F, F::Err> 
where F: FromStr

str である自身を受け取って,Result<F, F::Err> 型を返す.ただし,FFromStr trait を実装している*2,といったところだ.前述した std::str::FromStr::from_str と同じことをしているが,いわば見る視点が逆転しているのである.つまり,std::str::FromStr::from_str は,Self から str を,std::str::parse は,str から F を,それぞれ眺めている.

さて,前者は str に視点を定めればよいのは明らかだが,F は多相なので,立場が逆になるとうまくいかない.どこを見ればよいかわからないからだ.具体例を挙げると,当然ながら次のコードはコンパイルできない.

fn main() {
    let x = "42".parse();
    println!("{}", x.unwrap())
}

/*
error[E0284]: type annotations required: cannot resolve `<_ as std::str::FromStr>::Err == _`
 --> /var/folders/5h/7wt7yl7n24v72zsz77_3w_w00000gn/T/vKY0lB7/51.rs:2:18
  |
2 |     let x = "42".parse();
  |                  ^^^^^
*/

エラーメッセージに従って,型注釈を与えてやれば,コンパイルに成功する.

use std::num::ParseIntError;

fn main() {
    let x: Result<i32, ParseIntError> = "42".parse();
    println!("{}", x.unwrap()) // 42
}

これだけ見ると,単に煩わしさしか感じないのだが,Rust がおもしろいのは,多相である parse メソッドに,変換先の型の情報を渡して,型を限定する文法を提供している部分にある.これは turbofish と呼ばれ ::<> という形をしている.

fn main() {
    let x = "42".parse::<i32>();
    println!("{}", x.unwrap()) // 42
}

関数の型を直接指定しているのではなく,関数に型を,あたかも引数のように与えているという点に注目してほしい.これは Λ で抽象化された型 Fi32 という具体型を渡して,関数全体の型を決定するという操作に相当しているのだと思う*3

さて,Haskell にこのような文法はなかったかと考えたが,先日 Haskell Day 2016 に赴いた際に,SPJ が System F の話をしていて,GHC 8.0 から,Type Application という機能が導入された*4と話していたことを思い出した.これを用いると,Haskell でも以下のような書き方ができる.

{-# LANGUAGE TypeApplications #-}

import Text.Read (readEither)

unwrap :: Either a b -> b
unwrap = either undefined id

main = print $ unwrap (readEither @Int "42") -- 42

Rust の Result に対応して,Either を用いた.

ghci を使えば,多相な関数に型を適用して,単相な関数にする過程を実際に確かめることができる.

$ ghci
GHCi, version 8.0.1: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /Users/Ryota/.ghci
Prelude> :set -XTypeApplications
Prelude> :t read
read :: Read a => String -> a
Prelude> :t read "42"
read "42" :: Read a => a
Prelude> read "42"
*** Exception: Prelude.read: no parse
Prelude> :t read @Int
read @Int :: String -> Int
Prelude> :t read @Int "42"
read @Int "42" :: Int
Prelude> read @Int "42"
42

Hindley-Milner 型システムは強力であり,プログラマが直接型を明示しなければコンパイルできない,といった状況はそう多くない.しかしながら,幾つか例外があり,そのような場合に値ないし関数に,完全な形で注釈を与えることは,しばしば煩わしい作業である.let x: Result<i32, ParseIntError>(read :: String -> Int) 42 などと書かなくて済むように,このような仕組みを言語(または処理系)が提供してくれることは心強い.

以上の内容は,rustc 1.12.0 および ghc 8.0.1 での挙動に基づいている.

*1:引数として self を取らないもの.他の言語で言う static method や class method などに相当する.

*2:個人的にはこの where は,少なくとも初学者にとっては,Haskell における => よりもわかりやすいと思っている.Rust の影響を色濃く受ける Swift でも採用されている.

*3:この辺は全然詳しくないので,間違ってたらあとでこっそり教えてほしい.

*4:実際には,以前から内部的に実装されていたものを,一部使えるようにしたらしい.