トップ 最新 追記

Route 477



2013-04-01

[ruby] RubyでUTF8-MACをUTF-8に直す

プレビュー.appからMacVimにコピペしたら、「はじめに」が「はし゛めに」みたいになってしまって困ったので、 Rubyのワンライナで直してみた。

$ ruby -e 'print File.read(ARGV[0], encoding: "utf8-mac").encode("utf-8")' a.txt > b.txt

Ruby(>= 1.9)便利。

[ruby] RubyでMagic commentが必要なファイルを列挙する

Ruby 2.0からスクリプトエンコーディングのデフォルトがUTF-8になったので、文字列リテラルに日本語を使うときもマジックコメントを書かなくて良くなりました。

…というのは嬉しい変更なんですが、そうすると今度は「手元のRuby 2.0では動いてるけど、サーバのRuby 1.9.3で動かしたらinvalid multibyte char (US-ASCII)」みたいな事例が想像できるわけです。

ということで、rubyの-cオプションを使ってマジコメが必要なファイルを列挙するコマンドを書いておきます。ruby -cは、プログラムを実行せずパースチェックだけをするオプションです。

$ for a in **/*.rb; ruby -c $a

(追記:サーバ側で環境変数を設定できるシチュエーションなら、

$ RUBYOPT="-U" bundle exec rails server

とすることでマジコメなしでいけそう)


2013-04-02

[ruby] メソッドチェーンをinjectで書く

このへんを見て。

obj.foo(1).foo(2).foo(3)

みたいのってうまくmapとかでまとめられないけど、これは

(( obj.foo(1) ).foo(2) ).foo(3)

という左畳込みの形なので、injectを使って

[1,2,3].inject(obj){|sum, item| sum.foo(item)}

と書ける。というメモ。


2013-04-04

[ruby] Ruby 2.0のbsearchについて調べてみた

メモ

  • Array#bsearchとRange#bsearchがある
  • 条件にあう要素を二分探索で探し出す (Arrayの場合は、事前にソートしておかなくてはならない)
  • 条件にあう要素がなかった場合はnilが返る

$ cat junk.rb
ary = 10000.times.map{ rand }.sort
p ary.bsearch{|x| x > 0.5}
$ ruby junk.rb
0.5002038714292806

配列の中から、0.5を超える最初の数を探す。二分探索なので速い。配列の中身はソートされていなければならないのに注意。

Range#bsearchの方も同様に使える (検索対象がrng.to_aになったような感じ)。

$ cat junk.rb rng = (1..10000)
p rng.bsearch{|x| x > 5000}
$ ruby junk.rb
5001

応用例

これを利用して、git-bisectみたいのも作れるんじゃないかな。

bsearchを使うと「条件を満たす最初の要素」が取れるので、Range#bsearchを以下のように使うと、 「テストがNGになった最初のコミットID」を(git bisectのように)探しだすことができる。 Ruby 2.0が二分探索のアルゴリズムをうまく担当してくれるので、プログラマは判定条件だけ実装すれば良いので楽ちん。

commit_ids = %w(74fa16 e2be41 84f638 55130b 5a7a42 82ca3f)
puts "Bisecting #{commit_ids}"

rng = (0...commit_ids.length)
guilty = rng.bsearch{|i|
  commit_id = commit_ids[i]
  puts "Try #{commit_id}"
  print "Is it ok? [y/n]"
  $stdin.gets.chomp != "y"
}

puts "#{commit_ids[guilty]} is the bad commit."

ここでひとつ注意点を。Range#bsearchではなく、commit_ids.bsearchを使えばいいんじゃないの?と思うかもしれないが、 Array#bsearchはソートされていないといけないという条件があるので、インデックスの方をbsearchしないといけないのです。

find-anyモード

Array/Rangeのbsearchにはもう一つ、「find-any mode」というモードがあります。 ここまで見てきたものは「find-minimum mode」という、条件にあう最初のものを探し出すモードでした。 一方find-anyモードは、「一定範囲の要素をどれでもいいから一つ見つけたい」という場合に役立つモードです。 と書いておきつつ、それが具体的にどういう時なのかいい例を思いつかないのですが…。rdocにも、通常の用途では find-any modeの方を使うことになるだろうと書いてあります。

さっきのcommit_idsの例だと、「2012年10月15日のコミットが存在するか否か」を二分探索で検査したいようなケースで役に立つかな?


2013-04-07

[misc] enchant.jsの普及戦略がすごい

enchant.js、本が出たりして流行ってるなぁとは思ってたけど、意図的な戦略の上だったようだ。

  • 自社のオープンソースソフトウェア解説書を海外で出版するためにした8ステップ - UEI shi3zの日記
  • "予測は遠すぎても近すぎてもいけない"
  • "有る程度まで質を高めた跡で輸出する"
  • "東京でのローカルイベントにメディアを招き、全国に拡散"
  • 各地の地元に密着した協力者とローカルイベント(無料のプログラミング講座のような)を開催
  • 最初の一冊は自分で書くが、二冊目からは他の人に書いてもらう(エコシステムと多様性のため)
  • "印税ぶんを全て現物の書籍でもらい、寄贈を希望する学校・教育機関に関しては無償で配布"
  • 海外編:
    • "日本で何冊も本が出ているミドルウェアの、最初の英語版を出したいといえば話くらいは聞いてくれる"
    • "教育関係者とのコネクションができたら、「無料で講義をする」と売り込む"
    • "海外のイベントで主要なものには積極的に参加し、できれはスポンサーになる"
    • 優秀な翻訳者と査読者を根気よく探す ("日本人が書けば誰でも素晴らしい日本語にならないのと同様、アメリカ人に書かせても素晴らしい英文とはならない")

で、enchant.jsを普及させてどうするのかだけど、

人類が次の段階へ進化するにはもっと沢山のプログラマーが必要だ。

[http://d.hatena.ne.jp/shi3z/20130326/1364303398より引用]

ということらしい。


2013-04-08

[misc] TrelloでTODO管理

TODOツールはいろいろ試したあげく、最終的に「テキストファイル+TotalTerminal最強」っていう結論になったんだけど(どんなツールより自由度が高い:-/)、 でもやっぱり時にはWebでポチポチするタイプのTODOツールを使いたい気分になる。

で、TrelloをToDo/Doing/Done/Skippedに分けて使っているスクリーンショットを見て、なんだか良さそうだったので、趣味の開発を管理するのに使うことにしてみた。

ルールは以下。

  • Doing/Backlog/Done/Cancelledというリストを作る
    • 前はプロジェクトごとにリスト作ってたけど、こっちの方がずっと見通しがいい
    • プロジェクト名はprefixとして[foo]とか書いとけば十分
    • Done欄があると、「やった感」があっていい
  • これは必ずやる、と決めたことしかTODOには挙げない
    • 単なるアイデアをTODOと混ぜてしまうと消化が追いつかず、精神衛生上良くない
  • タスクに「重たさ」でラベルを付ける。1/2/4/8/16
    • Backlog欄は、「軽い順」にソートしておく。と、簡単にできるやつがすぐ分かって良い (と思うけどまだあまり活用してない)

これで、

  • メモ、予定、直近のやることリスト → plain text
  • 日付が確定している予定 → Google Calendar
  • 買い物リスト、家事関係 → ケータイのメモ
  • 開発関係 → Trello
  • 読みたい本 → Amazonのwishlist、カーリル
  • 旅行時の持ち物リストや買い物のための調査メモ → Evernote

という構成になった。


2013-04-09

[ruby] Ruby 2.0のRange#bsearchが無限区間の二分探索に対応している件

range.cのrdoc見てたら衝撃のサンプルコードが…

(0.0...Float::INFINITY).bsearch {|x| Math.log(x) >= 0 } #=> 1.0

0からFloat::INFINITYまでの間を二分探索する…だと?

実際にirbで試してみた。

irb(main):003:0> (0.0...Float::INFINITY).bsearch {|x|p x;  Math.log(x) >= 0 }
1.4999999999999998
1.305209627960036e-154
1.403377390202847e-77
4.59177480789956e-39
8.300922883092142e-20
3.528839442878961e-10
2.3007392883300778e-05
0.005874633789062499
(中略)
0.9999999999999982
0.9999999999999991
0.9999999999999996
0.9999999999999998
0.9999999999999999
=> 1.0

ちゃんと動きました。無限を無限のまま扱っている。凄い。ヤバイ。

実装上は、Floatを64bit整数にマッピングすることで実現しているらしい。


2013-04-14

[ruby][event] 頭のおかしいRubyプログラムのコンテストが開催されるぞ (5/18〆切)

5月末のRubyKaigiに合わせて、IOCCCのRuby版的なコンテストが開催されるようです。

「ようです」っていうか僕も審査員なんですが…。しかし他の審査員が強力すぎるので、どの方向からどんな投稿が来ても大丈夫な安心感があります。

mameさんのスライドや、本家にIOCCC入賞した人の記事とか見ると雰囲気が掴めるかもしれません。

なお、要件は「このプログラム、こんな風に動くんだ!」ということですので、本家IOCCC同様、たとえばワンライナでのエントリもアリです。(just another perl hackerみたいなね)

int _;main(O,l,o)char**l,**o;{_++>>9||main(1&(o?(int)o:O)|O*2,l,putchar(_%32?atoi(1[l])>>(7&O<<!o>>!o+29)&32<_|_==16?35:32:10)%10);}

CになくてRubyにあるものっていろいろ考えられるので(オブジェクト、組み込み・添付ライブラリ、RubyGems、多彩orマイナーな文法群などなど…)、いろいろなアプローチが考えられそうですね。

みなさまの創造性・技術力・(and/or)エンターテイメント性にあふれた投稿をお待ちしております。*1

*1 審査は作者名を伏せた状態で行われるため、審査員陣も投稿が許されています。投稿物のremarks.markdownの方には自分の名前を書かないように注意してください


2013-04-15

[ruby] whytheluckystiff.net が微妙に更新される

via @yukihiro_matz

最新の_why情報です

にアクセスすると謎のデータが…?

Public Print Queue SPOOL/DESOLEE2013-01-06T08:21Z SPOOL/TRUMPETS2013-04-12T19:43Z SPOOL/SOLICIT2013-04-12T20:10Z SPOOL/CAPRICE 2013-04-12T22:06Z SPOOL/HOMEWORK2013-04-12T23:19Z

_why先生OCaml始めたんでしょうか…?


2013-04-16

[misc] WiMAXを自宅回線として利用する際は「機器追加オプション」の有無に注意

自宅の回線を有線LAN(ケーブルテレビ)からWiMAXに切り替えて数年経つ。今月は契約更新月*1なので、回線を再契約して端末を買い換えようかなぁ*2*3と思っていたところ、契約中のBIC WiMAXが「機種変更キャンペーン」という、無料で新品の端末をくれるキャンペーンをやっていたので、それに申し込んでみた。その代わり今後1年間の解除料が通常より上がるらしいが (それを教えてくれるあたり良心的だ)、しばらくは解約する予定はないので問題ないだろう。

で、去年UQ WiMAXからBIC WiMAXに乗り換えるに当たっていろいろハマりどころがあったので、それをメモしておく。

WiMAXはMVNOを選ぶ必要がある

WiMAXは回線とサービス事業者が分かれているため、実際の申し込みはUQ WiMAX(公式)以外にも、BIC WiMAXとか@nifty WiMAXとか、適当な会社を選んで契約することになる。 サービス内容はどこも似たような感じで、「年間パスポート」みたいな名前の1年縛り・月額3880円のプランを選ぶのが基本になる。 だが、「機器追加オプションが提供されているかどうか」という点が事業者によって異なり、そこが人によってはクリティカルな違いになるので、以下で説明する。

「自宅でも外出先でも使いたい」場合

自宅のネット環境を固定回線からWiMAXにした主な理由は、「自宅でも外出先でもネットできる環境」をつくるのにWiMAXを使うのが一番安上がりだったからだ。 (今だとケータイでテザリングできたりするのでまた違うかも知れないが…。*4)

それを実現する方法はいくつかある。

1. 一つの端末を持ち歩く

まず最も単純な方法。1台のWiMAXルータをカバンに入れておき、家に帰ったら充電器に繋いで、家用回線として使う。

外でネットを使うことが毎日あるようなケースなら、これで問題ないだろう。1台持ちなので、「機器追加オプション」の有無も気にする必要はない。

2. 自宅と外出先で同時にネットしたい場合

家族がいるとか、自宅サーバを動かしているとかで、自宅の回線と外出時のネット使用を「同時に」行いたい場合は、回線を2つ契約する必要がある。(もちろんWiMAX端末も2つ必要) 事業者によっては「ファミ得パック」のようなオプションを選ぶと、普通に2回線契約するよりは割安になる。

3. 自宅用と外出先用の2端末でネットしたいが、同時にどちらかだけで良い場合

外でネットすることがあまり頻繁ではない場合、WiMAXルータを充電したり取り外したりするのが面倒なので、家用の端末と外用の端末を別に持ちたいことがある。 *5

このように、「2台持ちしたいが、同時には使わない」場合、事業者によっては「機器追加オプション」のような名前で、月額200円で2台目の端末を登録できることがある。 2011年の情報だが、kakaku.comの以下のスレッドが詳しい。

要約すると、

  • 機器追加オプションがあると、月額200円とかで2台目の端末を登録できる
  • 機器追加オプションがある事業者と、ない事業者がある (ので、WiMAX端末を2台持ちしたい人は注意)
  • 機器追加オプションがあっても、初期費用として105円かかる事業者とそうでない事業者がある (ので、使う月だけオプションを有効化したい人は注意)
  • 機器追加オプションがあっても、優先度設定 (2つの端末が同時にネットに繋ごうとしたとき、どちらが優先されるか設定できる機能) がない事業者がある (ので、家と外で使いたい人は外出前に家用端末の電源をオフにする必要がある??未確認)

ということのようだ。

で、

このような機器接続優先設定ができるのが私が知る限りヨドバシ、ビック、UQです。そして機器追加オプションで登録料を取られないのはビックとUQです。つまり月額200円で使わない月は解除が容易です。(中略)機器追加はダイワボウ情報システムでもできますね。

と書かれている。

一応、2013年現在も有効かどうか調べてみた:

(疲れたのでここまで。他にもあるかも知れない)

ということで、家用と外用の2台持ちを考えている人は、「機器追加オプションの有無」「登録料の有無」「優先度設定の有無」に注意しましょう。

おわりに

サービス内容が選べるのはいいけれど、こういう微妙な内容で差別化されると辛いですね…。

*1 解約しても違約金が取られない月のこと

*2 だいたいどの事業者も回線とセットで端末を買うと割引されるため、いったん解約して再契約することで、初期費用を考えても割安で端末が買える

*3 ただしWiMAX端末にはいわゆる「白ロム機」と「黒ロム機」があり、黒ロム機はその事業者専用なので、事業者を変えるとゴミになってしまう。白ロム機はどの事業者でも接続が可能

*4 使用しているケータイでのテザリングに容量制限がある場合は、WiMAXも選択肢になるだろう

*5 特に、Mountain LionになるまではUSBに挿すタイプのWiMAXルータが使えていたのでこれと家用と2台持ってたのでした


2013-04-17

[haskell][types] Haskellの型クラスの実現方法について調べてみた

型クラスの実装について調べていたら、1988年の「How to make ad-hoc polymorphism less ad hoc」という論文に行き当たった。

これによると、型クラスを使ったHaskellプログラムは、型クラスを使わない(代数的データ型のみの)プログラムに変換できるそうだ。*1

内容は、Haskellのclass構文とinstance構文の使い方を知っている人なら、上から順に読んでいけば理解できると思います。実装の話は3章からです。

最後のConclusionでは「型クラスはbounded quantierの一種と考えることができるが〜」のような専門用語が出てきますが、そのあたりが気になる人は「型システム入門」(TAPL)を読みましょう。*2

4274068854

4274069117

ad-hoc polymorphismとは

1章に説明がある。length [1,2,3]とlength [1.1, 1.2, 1.3]のような形のpolymorphismでは、length自体の実装はリストの中身がIntでもFloatでも同じで、パラメータとなる型の名前が変化するだけだ。こういうものをparametric多相という。

一方で、33と33.14では、乗算演算子はIntとFloatで実装が全く違う。こういうものをad-hoc多相という。

この論文では、Numの例とEqの例が出てくる。Numは「掛け算や足し算の演算子を、IntでもFloatでも使えるようにしたい」、Eqは「比較演算子を、IntでもFloatでも使えるようにしたい」という話。(型クラスを使うとIntやFloatに限らず、ユーザ定義の型にも+や==を定義できる)

変換の概要

class宣言は、型が持たないといけないメソッド一覧を定義する。それに対しinstance宣言は、実際にメソッドとして振る舞う関数群を与える。なので、これを代数データ型として定義してやる。

-- 足し算関数と掛け算関数を保持するデータ型を定義
data NumDict a = NumDict (a->a->a) (a->a->a)
-- Int用のメソッド群はこれ
NumDInt = NumDict addInt mulInt
-- Float用のメソッド群はこれ
NumDFloat = NumDict addFloat mulFloat</pre>

+*を実行するには、実際のメソッド関数が必要になる。なので、NumDictを第一引数にとる補助関数を作り、プログラム中での(+)(*)の呼び出しをそれの呼び出しへと置き換えてやる。 プログラム中の(+)(*)がIntを扱うのか、Floatを扱うのかは、型推論で分かっているはずなので、こういう変換ができる。

という感じ。

論文を読んでたときのメモが https://gist.github.com/yhara/5401423 にあります(あまり他の人の参考にはならないと思いますが)。

*1 88年の論文なので、現在のGHCもこのような方法で実装しているのかは未確認

*2 ちなみにTAPLは型クラスについては少し言及があるだけで、章はないです(なので論文を読んだ)。