水島雄太のブログ

個人的かつ雑多なブログです。

nicosearch をPyPIで公開

ニコニコ検索APIPythonから使用する簡単なラッパーライブラリを書いたので、試しにPyPIに公開してみました。

https://pypi.python.org/pypi/nicosearch https://github.com/ymizushi/nicosearch

  • インストール方法
pip install nicosearch
  • 使用方法
from nicosearch import SearchRequest, SearchQueryBuilder
query = SearchQueryBuilder(u'MMD').build()
print SearchRequest(query).fetch().get_contents()

optionはSearchQueryBuilderのキーワード引数として渡してやることにより実現できます。

今回書いたのはとても短い簡単なラッパーですが、一応世界中から pip installで簡単にインストールされる可能性があるので、 ソフトウェアを公開している、という実感が湧いてきました。

今まではただ単に楽しいからというだけでコードを書いていましたが、 これからは、公開できるソフトウェアをつくる、という意識を持つことも必要かな、と思いました。

Clojureのevalとmacroのパフォーマンスを比べる

Clojureには他の動的型言語と同様に文字列*1をプログラムとして評価出来るevalという関数があります。 Clojureにはマクロがありますし他の動的型言語と同様にevalは遅いだろうという推測は容易に出来ますので、evalを使わないといけない局面というのはそう多くないと思います。そもそもeval自体害悪であるとも考えられます。

ただプログラムを書いていてふとevalはどの程度遅いのかということが気になったので簡単に計測してみました。

clojureのevalとmacroで実行時間を比較

bashpythonclojure3つの言語が混在していますが、 10 * 10をeval版、macro版、関数版で10000回実行するプログラムを、20回実行しその平均を取っています。 dotimesはdotimesだけでどれぐらいの時間がかかるのかを計測するために入れています。

結果以下のようになりました。(単位はms)

eval: 8666.7311
macro: 2.3436
fn: 7.67685
dotimes: 0.896

実行時の環境、evalする対象、macroにする対象によって数値は多少変わるとは思いますが、 見て分かる通りmacro版、関数版に比べてeval版は1000倍以上遅いです。

あと関数版とマクロ版を比べたらマクロ版の方が早いように思いますが、 これはマクロが呼び出し元で展開され実行されるのに対して、関数版はユーザ定義の関数を呼び出さなければならないことによるものでしょう。 この辺り、ベンチマーク自体が即席のものであり、また実行時間も短いので、信頼性の高いものではありません。この辺りはちゃんと検証する必要があります。

ただ数回実行する即席で実行するプログラムならまだしも、同じような処理が走りパフォーマンスが重要になるような局面ではevalは絶対に使えないとは言えると思います。

*1:Clojureについてはクオートされている必要がある

Racketのdot記法を使う

Racketのdot記法は、基本的にリストの最後の要素の前に付きますが、 (1 . < . 2)と書くと、(< 1 2)等価に評価される*1同様にみなされるようです。

dot記法がペアを生成する(cons x y)の省略記法であることを考えると、 この記法は例外的に感じられます。

しかし、この記法を用いることにより、 中置記法っぽく、式を記述することが可能になります。 例えば、 (< 1 2)という式は (1 . < . 2)という表記をすることが出来るので 中置記法に慣れている方はこちらの方が見やすいのかもしれません。

試しにこの記法を使ってProjectEulerの第1問の解答を書きなおしてみました。

dot notation

しかしこれではいくら中置記法に近いと言っても、 かなり見にくくなってしまったように感じられます。

LISPの場合は、前置記法により、(= 1 1 1)(+ 1 2 3 4)といった、 任意の数の引数に対して、一つのオペレータを適用出来るという利点がありますが、 この場合その利点がなくなってしまいます。

<>といった比較関数、is-a?といった関数を使用時英語の語順に沿った評価順序*2式の構文にしたい場合に限定的に使用できるかもしれませんが、dot記法を使うと、スペースが余分に空いてしまいますし、 評価順序*3式の構文はLISPをしばらく使うだけで慣れによって全く気にならなくなるので、 これから使う機会はあまり無いように感じられました。

Pairs Lists and Racket Syntax

*1:コメント指摘により訂正

*2:コメント指摘により訂正

*3:コメント指摘により訂正

Lispは読みにくい以上に書きにくいと感じている人が多い説

Lispが流行らない理由として「括弧が多い」ということはよく挙げられる要素だと思います。

それでは何故「括弧が多い」ことが敬遠されるかというと、以下の2つが考えられます。

  • 読みにくい
  • 書きにくい

そのビジュアル面から、「括弧が多い」ことで「読みにくい」というイメージを持ちがちですが、 それ以上に「書きにくい」ことがネガティブな要素になっている気が最近してきました。

Lispのコードを書く際に、環境として必要となる要素については最低限以下のものが考えられます。

  1. 対応する括弧を強調表示
  2. 対応する括弧の削除
  3. 指定範囲への括弧挿入
  4. 対応する括弧にジャンプ
  5. 選択括弧のREPL実行

このような構成要素についてはエディタやIDEの設定をちょっと変えたり、プラグインを追加すればすぐに実現可能なことが多いのですが、プログラミング歴がそれなりに長い人でもあまり環境を最適化するという習慣を持っていない場合があり、 環境整備の敷居が想像している以上に高いのではないか。

一般的なプログラミング言語の場合、たとえメモ帳でコードを書くとしても プログラムが書けないということも無いと思いますが、 Lispの場合エディタ、IDEの支援がなければコードを書くのもままならない羽目に陥ることは 容易に想像できます。 個人的に1,2,3が無ければかなりきついです。

ということで、もし仮にLisp系の言語が流行るととなると、 言語以上に開発環境が重要になるような気がしました。

尤も、Lispが流行る、そんな日は未来永劫来ないのかもしれません。

しかし寿命で言うと、Lispは100年後もほそぼそと使われているんだろうなー、と予感させる言語であるようにも思います。

RacketのREPLをマシにする

Racket のREPLは素の状態では履歴もemacs標準キーバインドも使えないため、使い勝手が非常に悪いです。

とりあえず XREPL(eXtended REPL) を設定しましょう。

  • 設定方法
$ echo "(require xrepl)" >> ~/.racketrc

POSIX互換なら

$ racket

でREPLが起動する際に、~/.racketcを読み込みに行くようです。 正確に知りたい場合、(find-system-path 'init-file)で参照パスが取得できます。

XREPLにより、基本的なEmacsキーバインド、コマンド履歴、メタREPLコマンドが使用できるようになります。 どのようなコマンドが使用できるかは、 ,helpで参照できます。

Racketの場合、DrRacketで結構色々できちゃいますが、ちょっとしたスクリプティングならターミナルからREPLを起動した方が早いと思いますし、XREPLの使い勝手はかなり良いのでオススメです。

minosound 1.1 をリリース

minosound 1.1 をリリースしました。

バックエンドの部分はClojureで開発していて結構出来ているのですが、 はもうちょっと作りこみたいなーと思ったので、 とりあえずクライアントの部分だけデザイン、UIを変更したり、 WebVIEWでの更新情報告知機能などを追加したのだけをアップデートしました。

minosoundは結構他のことに浮気しつつまったりと進めていて、 一応開発はそれなりに継続は出来ていますがやっぱりスピードがなかなか出ないので、 がっつり浮気せずにやるのも必要だなーと思いました。

https://itunes.apple.com/jp/app/minosound/id645249293?mt=8&uo=4&at=10l8JW&ct=hatenablog

CloudBeesでのClojureプロジェクトのデプロイ方法

Clojureでよく使われているPaasとしてはHerokuが有名だと思いますが、最近はCloudBeesもよく使われているようなので、私もCloudBeesにClojureプロジェクトをデプロイしてみました。

CloudBeesはクラウド環境を操作するためのleiningenプラグインが用意されており、既存のClojureアプリケーションに設定を少し追加するだけで容易にデプロイが行えるようになっています。

1.Cloudbeesにてアカウントを取得 デプロイするために必要な情報はアカウント取得後、Accountページから参照出来る * API Key * Secret Key のみです。

2.project.cljに

  • :cloudbees-app-id
  • :plugins[[lein-cloudbees "1.0.3"] [lein-ring "0.8.7"]]
  • :ring {:handler your-app.namespace/entry-point}

を追加。

.~/.bees/bees.configに bees.api.keyとbees.api.secretを追加する

project.clj

3.リポジトリルートでlein cloudbees deploy

これだけでClojureプロジェクトがデプロイできてしまいます。

Herokuも簡単にデプロイ出来ますが、CloudBeesもleiningenプラグインが強力であるため、さほど変わらない手間でデプロイできます。

有料プランはどうなっているかわかりませんが、HerokuよりCloudBeesのほうが無料で使えるリソースが豊富なようです。体感でも分かるぐらいの違いはあるので、無料プランでもそれなりに使い倒したいという理由であれば、CloudBeesを選択するというのは賢いように思います。

おいしいClojure入門 (Software Design plus)

おいしいClojure入門 (Software Design plus)

IDEとVimと生産性

単純に生産性だけを考えると、静的型言語なら確実にIDEの方が生産性が高いように思うし、動的型言語でも最近だとIDEの方に軍配があがることが多いかもしれない。

ただ、実はプログラマにとって生産性はあんまり重要ではなくて、 それよりもどれだけモチベーションを維持出来るか、 どれだけプログラマとしての素養を底上げするかの方が重要では無いかと思っています。

例えばVimで何か気に入らないところがあれば、 ちょっと.vimrcをいじるだけで解決出来る事も多く、 Hackに対する敷居は高機能エディタの方が低いと思いますし、 よりHackしやすい環境に身を置く事の方が特に駆け出しの プログラマーに必要なのではないかと考えています。

また単純にVimの方がプログラミングモードに入る敷居が低いというのも個人的な印象としてあって、IDEを起動するのが面倒な時でも、Vimでささっとプログラミングに入ることが出来るのでモチベーションを維持しやすいです。

なので別に個人的にどちらが生産性高いかということには興味が無くて、 自分のモチベーションがどれだけ維持出来るかということを意識する方がよっぽど重要で、 有意義なのではないかと考えています。

迷路自動生成

先日リリースしたアプリで迷路自動生成を実装してみたので、 まとめてみます。

迷路自動生成の仕様としては、

  • 2次元平面の対角をスタートとゴールとする
  • スタートは必ず一つ
  • ゴールは必ずしも、一本の道で終わってなくても良い

以上の3点となります。

これらを踏まえた上で以下のようにステップ実行してみました。

ステップ実行してみると、1ステップごとに以下の点を考えるだけで、 全ての処理が終了するように思いました。

  1. 行き止まりではない場合、ランダムで分岐を選択
  2. 行き止まりだった場合、選択していない分岐まで戻る
  3. もし全ての点を走査したら処理を終了

データ構造としては、

  • X座標、Y座標、前の点、探索済みフラグを保持しておく
  • 再帰を使って前の点への参照を作っていく

以上で、迷路を単純な木構造として表現出来そうです。

このよう方針にてPythonで実装してみました。

実際の動作としては、既にiPhoneで実装したものをリリースしていますので、 それで確認してみてください。

minosound

このアルゴリズムの問題点としては、

  • ゴールの深さが迷路が生成されるたびに変わる。
  • 分岐が浅くなりやすい。

といったことがあるため、 今後何かしらのアルゴリズムの修正が入るかもしれません。

Homebrewでインストールしたleiningen1.xからleiningen2.xへのUpgrade

2013/04/04現在、Homebrewでインストールされる leiningenが1.x系列なので2.x系列にUpgradeしてみました。

ほぼleiningen/wiki/Upgradingの手順通りです。

直接Cellarいじくっていいのかよくわかりませんので、こうした方が良いよというのがあれば指摘していただけるとありがたいです。

$mkdir /usr/local/Cellar/leiningen/2.1.2/bin
$brew install wget
$wget -O /usr/local/Cellar/leiningen/2.1.2/bin/lein https://raw.github.com/technomancy/leiningen/stable/bin/lein
$ln -s /usr/local/Cellar/leiningen/2.1.2/bin/lein /usr/local/bin/lein
$chmod 755 /usr/local/bin/lein

ここから ~/.lein/plugins/ にあるプラグインを ~/.lein/profiles.clj に追加していきます。

~/.lein/bin/ が以下のようになっていたので、 compojure-lein-template-0.2.0.jar lein-newnew-0.2.6.jar swank-clojure-1.4.2.jar

~/.lein/profiles.clj に以下のように記述します。

{:user {:plugins [
    [lein-immutant "0.18.0"]
    [compojure/lein-template "0.2.0"]
    [lein-newnew "0.2.6"]
    [swank-clojure "1.4.2"]]}}

これで完了です。

今回immutantというアプリケーションサーバをインストールするために leiningen2.x系列にupgradeしたので、

$lein install immutant

で問題なくインストール出来ました。

ちなみに、~/.lein/profiles.cljは今後編集していくと思いますので、 dotfilesに組み込みました。

設定したい方は以下のリポジトリの.gitignore、.lein/profiles.clj、参考にしていただければと思います。

ymizushi/dotfiles

zshでgit checkoutを叩いた時のリモート補完を無効

最近bashからzshに移行したが、 zshではデフォルトでリモート補完が有効になっているので、 git checkout でブランチ名補完を行おうとした際に、 リモートのブランチ名を探しに行ってしまう。 そのため補完が完了するまで入力を受け付けないという事が頻発するので、 無効にする方法を探してみた。

StackOverflowで見つけた記事によると、

.zshrcに compdef -d git checkout

を追記するだけで補完を無効に出来る事はわかったが、 こうするとローカルブランチも補完が無効になってしまう。

誰しもが無効にしたくなると思ったんだが、なんでぱっと情報出てこないんだろうか。

参考: http://stackoverflow.com/questions/12175277/disable-auto-completion-of-remote-branches-in-zsh

Vimでカレント列から行末までをヤンク

Vimではノーマルモードで Dでカレント列から行末までを削除してヤンク、 Cでカレント列から行末までを削除してヤンクして挿入モード に入るのに、 カレント列から行末までをヤンクするコマンドが y$ でしか出来ないので、 nnoremap Y y$ しておけばいいと思います。

Pythonのitems()とiteritems()の違い

Python2.xの辞書オブジェクトに対する組み込みメソッド、 items()はkeyとvalueをtupleに格納したlistを生成して返すのに対して、 iteritems()はイテレータを返す。

items()はいちいちリストを生成する分、オーバーヘッドがかかるので、 基本的にiteritemsを使ったほうが良いっぽい。

一方、イテレータはスライスが使えないので、 スライスで要素の範囲指定をしたいときは、items()で取ってこないといけない。

ただ、3.xではitems()もイテレータを返すようになり、iteritems()は廃止になったそうです。

参考: http://stackoverflow.com/questions/10458437/python-what-is-the-difference-between-dict-items-and-dict-iteritems

パーフェクトPython
パーフェクトPythonPythonサポーターズ

技術評論社 2014-10-31
売り上げランキング : 15928


Amazonで詳しく見る
by G-Tools
Pythonプロフェッショナルプログラミング 第2版
Pythonプロフェッショナルプログラミング 第2版株式会社ビープラウ

秀和システム 2015-02-28
売り上げランキング : 4750


Amazonで詳しく見る
by G-Tools

git rebase

  • git rebaseするときの注意点

git rebaseはbranchを切ってからのcommitを全て書き換えてしまう(ハッシュも違うものになる)ので、リモートブランチにpushしてから、git rebaseを行うと、そのままではpush出来ず、
間違えてpull してしまうと、同じ内容のコミットが別のコミットとして扱われ、同一の内容が重複してマージされてしまう。
とりあえず、

  1. 公開ブランチでは絶対にgit rebaseしない。
  2. pushに失敗したら、リモートとローカルのコミット履歴を確認した上で、git push -fを行う(確認をせずにpush -fを行わない。もし他の人がそのブランチにcommitしていた場合、最悪そのcommitが失われる。)
  3. git rebaseした後は、pushするまで絶対にpullは行わない

この位守っておけば、大失敗はしないかな?

何にせよ、git rebaseはgitの仕組みをちゃんと理解してないと危険だよな。