反省はしても後悔はしない

Vim とか備忘録とか。それと関数型言語勉強中

Functional 花見 2013 に行ってきた

Functional 花見 2013 に行ってきました。
天気は良いし、桜は満開で最高のお花見日和でした。
そして、なぜか電源もWi-Fiもあるったのでハッカソンにも最適な環境でした。

本日の成果

  • @ さんに opam という、OCaml 用のパッケージ管理ツールを教えてもらいました。早速、インストールしようとしたらハマッてしまったのですがそれも mzp さんが一瞬で解決してくれました。mzp さんすごい。
  • @ さんから F# から JavaScript にコンパイルする FunScript というものの存在を教えてもらいました。コンパイルだけでなく、TypeScript の型定義ファイルから TypeProvider で F# の型をつくることもできるらしいです。時間があれば遊んでみたいです。
  • TaPL 和訳本をちょっと解説してもらいました。あと、@ さんと @ さん(多分)に一番最初の演習問題を解説してもらいました。TaPL の訳本は本屋で少し立ち読みして第2章の最初のページですでに圧倒されてしまって買うのを諦めてたのですが、今日の話では2章はとりあえず流して3章から読めばよいとのことだったので今度時間があるときに買って勉強してみようと思います。
  • @ さんと @ さんにそそのかされ勧められて Coq をインストールしようとしました。前半で opam を入れていたので opam install coq で簡単に入るはずだったのですが、あまりのビルドの遅さにバッテリーが耐え切れずにインストール中に強制シャットダウンとなってしまいましたが・・・。→お家帰ってからちゃんと入れました! Coq も今までは名前だけ知っているだけでよく分かっていなかったのですが、今日話を聞いてやっと Coq の概要を理解しました。少し興味が湧いたので触ってみたいです。
  • @ さんが幻の焼酎である「森伊蔵」を持ってきてくれたので少しだけ頂きました。地元鹿児島でもなかなか手に入らないだけあってすごくおいしくて飲みやすい焼酎でした。sunotora さんありがとうございました。
  • 来栖川電算さんのオフィス見学をさせて頂きました。他社さんのオフィスを見学する機会なんてほとんどないので、新鮮でした。広々とした机にデスクトップマシンがどーんとあり、まさにエンジニアのためのオフィスといった感じで、羨ましかったです。来栖川電算さんありがとうございました。


上に書いた以外にもいろいろ興味深い話をいろいろ聞かせて頂きました。花見のはずなのに勉強会以上に勉強になった気がします。みなさんありがとうございました。

課題としては、インプットばかりで自分からアウトプットが全然ないことですかね〜。もっと勉強してアウトプットもできるようになりたいです。

最後に、主催のITプランニングさん、電源確保してくださった @ さん、あと前日の夜から場所取りをしてくださった方、買い出しに行ってくださった方ありがとうございました。

今更ながら F# で逆 FizzBuzz を解いてみた。それと List モナド

背景

先週のなごやかScala #9にて、逆 FizzBuzz 問題というものを Scala で解いたものをコードレビューするというのがありました。
はてなダイアリーふっかつと逆FizzBuzz問題をScalaで解こう(前編) - スノトラさんのつれづれ日記
元ネタは多分これ
逆FizzBuzz問題 (Inverse FizzBuzz) - 猫とC#について書くmatarilloの雑記


私はその時は問題を知らなかったのでコードレビューの時は聞き流していたのですが、帰ってから調べてみたら面白そうだったので挑戦してみることにしました。Scala で書くのは sunotra さんにおまかせするとして、私は F# でやってみました。

ひけっていけいさん → List モナド

元ネタの Scala のコードを読むと [1..1], [1..2], ... , [1..100], [2..2], [2..3], ... というリストのリストから答えとなる文字列にが合致するものを探すアルゴリズムになっています。(正確にはすべての要素を FizzBuzz 化させたものを Map にしていて、入力の文字列のリストをキーとして答えを取り出している)
答えの候補となるものをとりあえず全部並べていく = 非決定計算ということで、コンピュテーション式を使った List モナドで実装してみました。
実はコンピュテーション式よくわかっていないので*1、List モナドのところは以下を参考にしました。
F#で順列(Permutation)と組み合わせ(Combination)。YOU、Listモナドしちゃいなよ。集合モナドもあるよ。 - Bug Catharsis

書いてみた

let fizzbuzz x =
    match (x%3, x%5) with
    | 0, 0 -> ["FizzBuzz"]
    | 0, _ -> ["Fizz"]
    | _, 0 -> ["Buzz"]
    | _, _ -> []

let tofizzbuzz xs = List.collect fizzbuzz xs

type ListBuilder() =
    member this.Bind (m, f) = m |> List.map f |> List.concat
    member this.Return x = [x]
    member this.Zero () = []

let list = ListBuilder()

let answers input = list {
    let! start = [1..100]
    let! end = [start..100]
    if tofizzbuzz [start..end] = input then
        return [start..end]
}

let inverse_fizzbuzz input =
    match answers input with
    | [] -> []
    | xs -> List.minBy List.length xs

printfn "%A\n" <| inverse_fizzbuzz ["Fizz"; "Buzz"; "Fizz"; "FizzBuzz"; "Fizz"; "Buzz"]
(* [9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20] *)

上のコードの answers のところでコンピュテーション式を使っています。本来なら2重ループになるところがすっきり書けていて素敵ですね。

逃げ

F# 力低いので上のコードは突っ込みどころ満載かも知れません。

*1:なんで Zero がいるの?とか

Vim でコピペするときの Tips

この記事は Vim Advent Calendar 2012 の 40 日目の記事です。
昨日は @kokukuma さんのなんかvimがセグメンテーションフォルト吐いたんですけど。。でした。

はじめに

プログラミングに限らず、何かを書くときにコピー&ペーストってよく使いますよね。Vim でも当然その機能はありますが、Vim の場合はレジスタという仕組みによってさらに便利に使うことができます。
今回は、私が最近覚えてすごく便利に思ったコピー&ペーストに関する小ネタを書きます。

前提知識 レジスタとは

文字列を y でコピー(Vim ではヤンクといいます)すると、その文字列は無名レジスタに蓄えられます。d とか c とかで削除した時も同様です。無名レジスタに記録された文字列を貼り付けるには単純に p や P を使います。
"ayy とか "bdw とすると、明示的に a レジスタや b レジスタに書き込みます。こうすると、たくさんの文字列を記録させることができます。明示的にレジスタを指定して貼り付ける時は "ap や "bP などとします。
詳しくは :h registers してください。
ちなみに :reg とすると、現在のレジスタの一覧を参照できます。

0(ゼロ)レジスタで同じ文字列を何度も貼り付ける

y でヤンクした文字列をいろんな場所に貼り付けるということはよくあると思います。普通にいろんな場所に p で貼り付ければいいのですが、困るのが途中で編集をして関係ない文字列を削除してしまった時。せっかくヤンクした文字列が上書きされてしまって貼り付けられなくなってしまった。
実はヤンクされた文字列は 0 というレジスタにも自動的に入ります。そして、削除などでは 0 レジスタは使われません。なので、

"0p

と打てばヤンクされた文字列をいつでも使うことができます。

別解

明示的に _ レジスタに書き込むと無名レジスタは使用されなくなります。なので削除するときに "_dd などとすると、その後も単純に p でヤンクした文字列を貼り付けることができます。

* レジスタクリップボードと連携する

ネットの海をさまよっていたら、Vim のナイスな設定を見つけた!よし、自分の .vimrc にコピペしよう。
あまりお行儀は良くないですが、ブラウザなど他のアプリケーションにある文字列を Vim で使うにはクリップボードを使うと便利です。ブラウザなどで Ctrl+C でコピーしたあと、Vim

"*p

とすると、クリップボードの内容を貼り付けることができます。*1
逆にクリップボードに文字列を書き込むには "*yy などとします。*2

<C-R>でインサートモードから貼り付け

インサートモードにいるときに、ヤンクした文字列を貼り付けたくなったら・・・?インサートモードで

<C-R>"

とすると、ノーマルモードに戻らずに無名レジスタの内容を貼り付けることができます。<C-R>のあとはレジスタを指定できます。<C-R>a で a レジスタの内容を貼り付けます。無名レジスタのときは " です。
あと、<C-R> による貼り付けはコマンドモードでも使えます。

/ レジスタでさっき検索した文字列を挿入

/ や ? で検索した文字列は自動的に / というレジスタに格納されています。これが何の役に立つかというと、正規表現をつかって置換をするときに便利です。
まず、/ を使って正規表現を検索して自分が望む文字列を検索できているかを確認します。

以下を入力すると・・・

:%s/<C-R>/

以下のように即座に置換コマンドにするできます。

追記

単純に前回の検索パターンを使って置換を行うには下記で良いとのこと。

:%s//hoge/

id:deris さん、情報ありがとうございました。

コマンドモードでカーソル位置の単語を貼り付け

地味だけどすごく便利な機能です。
下の図のような(exists にカーソルがある)ときに

このように入力すると

:help <C-R><C-W>

exists 関数についてのヘルプを引くことができます。

おわりに

いかがだったでしょうか。Vim を使いこなしている方には結構当たり前なことだったかもしれないですが、私は最近知ったので半分は自分の備忘録として書きました。
間違いや補足、他にもこんな事出来るよというのがあればコメントいただけると幸いです。

次回は @Qvic_ さんです。

*1:* レジスタがうまくいかないときは + レジスタだとできるかも?

*2:set clipboard=unnamed すると自動でクリップボードにも書き込まれる

Vim で使える Ctrl を使うキーバインドまとめ

キーマップに Ctrl キーを使うものを割り当てたいんですが、既存の機能と衝突するのが怖いので調べてみました。

keybind normal visual insert
<C-a> 数字を加算 なし さっき挿入した文字を挿入
<C-b> 1ページ上にスクロール 1ページ上にスクロール なし*1
<C-c> (検索)コマンドの中止 visual モードの終了 insert モードの終了
<C-d> 半ページ下にスクロール 半ページ下にスクロール 字下げの削除
<C-e> 1行下にスクロール 1行下にスクロール カーソルの下の行の同じ位置の文字を挿入
<C-f> 1ページ下にスクロール 1ページ下にスクロール インデントの再調整
<C-g> カーソル位置とファイルの状態表示 セレクトモードへ移行 1行下の、挿入開始位置と同じ列へ移動
<C-h> カーソルを左に移動 カーソルを左に移動 カーソル前の文字を削除
<C-i> ジャンプリスト中の新しいカーソル位置へ移動 なし =<Tab>
<C-j> =<NL> 1行下に移動 =<NL> =<NL>
<C-k> なし なし 合字を入力
<C-l> 再描画 なし なし*2
<C-m> =<CR> 1行下の先頭に移動 =<CR> =<CR>
<C-n> 1行下へ移動 1行下へ移動 補完(後方検索)
<C-o> 古いカーソル位置へ移動 なし 1つコマンドを実行して、挿入モードに戻る
<C-p> 1行上へ移動 1行上へ移動 補完(前方検索)
<C-q>*3 =<C-v> =<C-v> =<C-v>
<C-r> リドゥ なし レジスタの内容を貼り付け
<C-s>*4 なし なし なし
<C-t> タグスタックをたどる なし 字下げの挿入
<C-u> 半ページ上にスクロール 半ページ上にスクロール 現在の行の入力文字を全て削除
<C-v> 矩形 visual モードへ移行 矩形 visual モードへ移行 次に入力した文字を入力
<C-w> ウィンドウコマンド ウィンドウコマンド 前の単語を削除
<C-x> 数字を減算 なし CTRL-X モードへ (補完やスクロール)
<C-y> 1行上にスクロール 1行上にスクロール カーソルの下の行の同じ位置の文字を挿入
<C-z> サスペンド サスペンド なし
<C-^> alternate ファイルを開く (= :e #) なし IM切り替え
<C-]> カーソル位置の単語でタグジャンプ カーソル位置の単語でタグジャンプ 短縮入力のトリガ
<C-@> なし なし さっき挿入した文字を挿入して insert モードを終了

意外と insert モードでも Ctrl を使ったコマンドがあるのは知らなかったなぁ。

*1:+revins でコンパイルされたときは revins の切り替え

*2:insertmode がオンのときはノーマルモードへ移行

*3:ただし、端末によっては使えない

*4:ただし、端末によっては使えない

vim-smartinput と vim-endwise が競合した時の対処法

vim-smartinput も vim-endwise もどちらもすごく良いプラグインなのですが、2 つ一緒に使ってると smartinput の C 系の中括弧入力がうまくはたらかなくなってしまいました。

↓正常時

if (hoge) {
  #
}

vim-endwise と競合時

if (hoge) {
#}

原因

vim-smartinput も vim-endwise もどちらもインサートモードの <CR> をマッピングしているのでそれが競合したようです。

対処法

vim-endwise が対応する filetype のみでバッファローカルなマップを定義します。

let g:endwise_no_mappings = 1
autocmd CohamaAutoCmd FileType lua,ruby,sh,zsh,vb,vbnet,aspvbs,vim imap <buffer> <CR> <CR><Plug>DiscretionaryEnd

とりあえずは、これで治りました。

Scala の関数の変位について調べてみた

ジェネリックの変位についてはいろいろ資料とかあるんだけど、関数の変位ってどうなってるのか少し疑問だったので調べて見ました。

どういうこと?

たとえば、以下のようなイベントがあったときに

def onLoad(callback: Event => Unit)
def onClick(callback: MouseEvent => Unit)

以下のように呼べるかということです。(MouseEvent は Event を継承しています)

def handler(e: Event) {
  alert(e.message)
}
onLoad(handler)
onClick(handler)

onLoad に対して、Event => Unit な関数を渡すのはいいとして、MouseEvent => Unit な関数を受け取る onClick に対しても呼び出してもいいのかということですね。(これは「反変」の例)

いろいろためしてみた

共変・反変の説明は他に譲るとして、いろいろ試してみました。

class Base {}
class Derived extends Base {}

def hoge(func: Derived => Base) {}

def dd(d: Derived): Derived = new Derived
def db(d: Derived): Base = new Base
def bd(b: Base): Derived = new Derived
def bb(b: Base): Base = new Base

hoge(db) // 完全に一致
hoge(dd) // 戻り値の型が派生型 (共変)
hoge(bb) // 引数の方が基本型 (反変)
hoge(bd) // 共変 + 反変

結果として、上記は正常にコンパイルできます。メソッドの引数については「反変」、戻り値については「共変」が常に許されるみたいです。

LinuxMint13 で gvim をコンパイル

最新版の gVim が使いたいなと思い、gVim をコンパイルしようとしていろいろつまづいたので備忘録として書いておきます。
OS は LinuxMint13 ですが、多分 Ubuntu でも似たような感じになると思います。

mercurial のインストール

$ sudo apt-get install mercurial

リポジトリから Vim のソースを取ってくる

$ cd src
$ hg clone https://vim.googlecode.com/hg/ vim
$ hg pull
$ hg update

ソースリポジトリを追加

$ vim /etc/apt/souces.list
  deb http://archive.ubuntu.com/ubuntu/ precise main restricted universe multiverse
+ deb-src http://archive.ubuntu.com/ubuntu/ precise main restricted universe multiverse
  deb http://archive.ubuntu.com/ubuntu/ precise-updates main restricted universe multiverse
  deb http://security.ubuntu.com/ubuntu/ precise-security main restricted universe multiverse

apt-get をアップデート

$ sudo apt-get update

必要なライブラリをインストール

$ sudo apt-get install libncurses5-dev
$ sudo apt-get build-dep vim

ビルドする

$ cd vim
$ ./configure --prefix=~/app/vim73 \
  --with-features=huge \
  --enable-multibyte \
  --enable-fontset \
  --enable-gui=gnome2 \
  --enable-pythoninterp=yes \
  --enable-rubyinterp=yes \
  --disable-selinux
$ make
$ make install

パスを通す

.zshrc など

export VIM_HOME=~/app/vim73/bin
export PATH=$PATH:$VIM_HOME