コンピュータやソフトウェアのあれこれ@道民(&元道民)
hiratara
This user hasn't shared any biographical information
Homepage: http://d.hatena.ne.jp/hiratara/
Posts by hiratara
退職します
2月 10th
今日が今勤めている会社の最終出社日となりました。
思えば6年前、次期システムをPHPで開発するつもりだと話していた当時のスタッフにPerlを使うよう誑かしたアドバイスしたのが始まりで、まさかここまで付き合いが長くなるとは思ってもいませんでした。
在職中は0からシステム構築をする機会を与えられた上、BTSやCIを始めとする開発ツール・フローの導入、書籍購入の自由化、20%ルールの実践、社内勉強会の開催、社外勉強会への参加の奨励など、エンジニアがやりたいと思ったことをどんどん実践できる権限を与えられ、大変刺激的に過ごすことができました。
お世話になった職場の皆様に、この場を借りて感謝致します。どうもありがとうございました。
[java][scala]Scalaの空括弧とUnit
2月 2nd
Unit周りでハマったのでメモ。
まず、() => Any という型はあるが、()という型はない。
scala> def id(x: () => Int): () => Int = x id: (x: () => Int)() => Int scala> def id(x: ()): () = x <console>:1: error: '=>' expected but ')' found. def id(x: ()): () = x ^
Unit型の唯一の要素が()である。
scala> ().isInstanceOf[Unit] res67: Boolean = true
() => Any は Unit => Any とは違う。
// 型が違って代入できない scala> val emptyParentheses: () => Any = { () => 10 } emptyParentheses: () => Any = <function0> scala> val unit: Unit => Any = emptyParentheses <console>:17: error: type mismatch; found : () => Any required: Unit => Any val unit: Unit => Any = emptyParentheses ^ // 型が違って代入できない scala> val unit: Unit => Any = {(u: Unit) => 20} unit: Unit => Any = <function1> scala> val emptyParentheses: () => Any = unit <console>:17: error: type mismatch; found : Unit => Any required: () => Any val emptyParentheses: () => Any = unit ^
が、Unit => Any は空括弧で呼び出すことができる。
scala> def one(u: Unit): Int = 1
one: (u: Unit)Int
scala> one(())
res68: Int = 1
// これ、なんでエラーにならないのかわからず (Value Discardingから??)
scala> one()
res69: Int = 1
scala> one
<console>:18: error: missing arguments for method one in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
one
^
// これは、要請がUnit型なら{ e; () }に変換するルール(Value Discarding)より
scala> one("DUMMYYY")
res71: Int = 1
// これもValue Discarding から??
scala> one(1, "XXX", Nil)
res72: Int = 1
[scala][java]Scalaのvalとvarとdef
2月 2nd
valは定数、varは変数、defはコード、というのが大まかな理解になる。これらは名前空間を共有しているので、定数、変数、コードに同じ名前をつけることはできない。ただし、JSやPythonのように単純にフィールドにメソッドオブジェクトが入っていると思うとハマる部分があるので、その辺を含めて調べたことをメモ。(なお、このエントリは 2.9.1.final での挙動について書いている。)
クラス定義のvar、def、val はメソッド
valとvarはfinal付き、final無しの変数として解釈されると思われるが、クラスのフィールドとして定義した場合にはJVM上ではメソッド経由でアクセスすることになる。ので、abstract defをvarやvalでオーバーライド*1したりできる。
class ValVarDef {
val x = 1
var y = 2
def z = 3
}
% javap -private ValVarDef public class ValVarDef extends java.lang.Object implements scala.ScalaObject{ private final int x; private int y; public int x(); public int y(); public void y_$eq(int); public int z(); public ValVarDef(); }
メソッドと関数型のフィールドは違う
JSなどと違い、def hoge(x: String): Int (メソッド)とdef hoge: String => Int (関数オブジェクトのフィールド)はまったく違うもの。
// 名前付き引数で呼べる scala> def hoge(x: String): Int = x.length hoge: (x: String)Int scala> hoge("abcde") // ←一見同じ振る舞いをするように見える res140: Int = 5 scala> hoge(x = "abcde") res141: Int = 5 // 名前付き引数で呼べない scala> def hoge: String => Int = x => x.length hoge: String => Int scala> hoge("abcde") // ←一見同じ振る舞いをするように見える res142: Int = 5 scala> hoge(x = "abcde") <console>:11: error: reassignment to val hoge(x = "abcde") ^ // 引数には自動的に名前がつく (コメント欄参照) scala> hoge(v1 = "abcde") res3: Int = 5
JVMのレベルで見ると、前者はメソッドに直接処理を記述したもので、後者は処理を記述されたFunctionNオブジェクト(ここでは MyTest$$anonfun$hoge2$1)を返すメソッドになる。
class MyTest { def hoge1(x: String): Int = x.length def hoge2: String => Int = x => x.length }
public class MyTest extends java.lang.Object implements scala.ScalaObject{ public int hoge1(java.lang.String); public scala.Function1 hoge2(); public MyTest(); } public final class MyTest$$anonfun$hoge2$1 extends scala.runtime.AbstractFunction1 implements scala.Serializable{ public static final long serialVersionUID; public static {}; public final int apply(java.lang.String); public final java.lang.Object apply(java.lang.Object); public MyTest$$anonfun$hoge2$1(MyTest); }
defの定義で、引数なしと空括弧は微妙に違う
def hoge = 1 と def hoge() = 1 は振る舞いが微妙に違う。特に関数オブジェクトが入っている場合。
scala> def func1 = (_: Int) + 1
func1: Int => Int
scala> def func2() = (_: Int) + 1
func2: ()Int => Int
// 引数無しで定義すると"func1()"では呼び出せない
scala> func1
res136: Int => Int = <function1>
scala> func1()
<console>:9: error: not enough arguments for method apply: (v1: Int)Int in trait Function1.
Unspecified value parameter v1.
func1()
^
// 空括弧で定義すると"func2()"でも"func2"でも呼び出せる
scala> func2
res138: Int => Int = <function1>
scala> func2()
res139: Int => Int = <function1>
// func1は括弧付きで呼び出せないので、意図したように解釈される
scala> func1(5)
res131: Int = 6
// func2を5を引数として呼び出したと解釈されるため、エラーとなる
scala> func2(5)
<console>:9: error: too many arguments for method func2: ()Int => Int
func2(5)
^
scala> func2()(5)
res135: Int = 6
=> はJVM上では関数オブジェクト
まあそうだよね。
class MyTest { def hoge1(x: Int) = x + 1 def hoge2(x: => Int) = x + 1 def hoge3(x: () => Int) = x() + 1 }
public class MyTest extends java.lang.Object implements scala.ScalaObject{ public int hoge1(int); public int hoge2(scala.Function0); public int hoge3(scala.Function0); public MyTest(); }
lazy val はJVM上ではメソッドとして定義される
まあそうだよね。
class MyClass { def hoge1: Int = { val x = 1 lazy val y = 1 x + y } def hoge2: Int = { val x = 1 lazy val y = 1 x + y } }
public class MyClass extends java.lang.Object implements scala.ScalaObject{ public int hoge1(); Code: ..略.. 24: invokespecial #21; //Method y$1:(Lscala/runtime/IntRef;Lscala/runtime/VolatileIntRef;)I ..略.. 27: iadd 28: ireturn public int hoge2(); private final int y$1(scala.runtime.IntRef, scala.runtime.VolatileIntRef); private final int y$2(scala.runtime.IntRef, scala.runtime.VolatileIntRef); public MyClass(); }
objectはstatic
objectはシングルトンオブジェクトを定義するものだが、JVM上ではstaticとして解釈される互換性のためstaticメソッドも用意される。
class MyTest { val inClass = 1 } object MyTest { val inObject = 2 }
% javap MyTest MyTest$ public class MyTest extends java.lang.Object implements scala.ScalaObject{ public static final int inObject(); public int inClass(); public MyTest(); } public final class MyTest$ extends java.lang.Object implements scala.ScalaObject{ public static final MyTest$ MODULE$; public static {}; public int inObject(); }
*1:コメント欄も参照
[perl][perl+web]Test::LeakTrace についてメモ書き
1月 5th
ハマったので未来の自分のためにメモ書きを残しつつ、今年もよろしくお願い致しますm(_ _)m。
Test::LeakTraceの特性
Test::LeakTrace で、以下のテストは通る。
my %x; no_leaks_ok { $x{x} = undef };
しかし以下のテストは通らない。
my @x; no_leaks_ok { push @x, undef };
これは、@x にエントリが増えた分がリークとしてカウントされるから。じゃあ前者はなぜ大丈夫なのかというと、no_leaks_ok はブロックを2回実行して2回目でリークをカウントするせい。1回目の実行で%xのバケットが1つ増えるが、2回目以降は再利用するのでリークとしてカウントされない。
あと、次のコードは "not ok 1 - leaks 1 <= 0" と言ってる癖にダンプを表示しない。
my %x; my $k = 0; no_leaks_ok { $k = ($k + 1) % 2; $x{$k} = undef; };
これはダンプを作る際にさらに改めて2回ブロックを実行する仕組みになっているため。この現象は2回目の呼び出しまではメモリが増加するけど3回目以降は増加しないような場合に起こる。
Test::LeakTrace はこのように複数回ブロックを呼び出してリークを判定・調査する特性があるので、メモリの使い方が安定した状態で呼んだ方が懸命である。
Test::LeakTrace と AnyEvent
AnyEvent のコードはコールバックを中心に書くため、リークしやすい。なので、 Test::LeakTrace でリークしてないことを確かめるのはよいプラクティスだと思う。
しかし AnyEvent は実際の初期化処理を任意のメソッドの使用時にまで遅らせている。そのため、任意のタイミングで初期化処理が走る可能性があり、それが Test::LeakTrace の結果に影響を及ぼすかもしれない。よって、 AnyEvent::detect を先に呼んで初期化を終わらせておいた方が変にハマらずに済む(気がする)。
[メモ][planet]2011年のまとめ
12月 29th
2009年のまとめはあるのに2010年のまとめがないことに気がつきましたが気にしない。
- CLTT読書会に割と出た
- #yhiosに割と出た
- 各種.pmに割と出た
- スタートHaskellに少し出た
- Awodey読書会に少し出た
- Java EE勉強会に少し出てClojureした
- GAEにパッチ送った
- (お仕事で)レガシーなのをPSGI化した
- Git勉強会で話した
- 揺れた
- 計画停電時間検索ツールを
DIS手伝った - (お仕事で)iPhoneアプリ書いた
- Coqに触れた
- 論理と計算のしくみ読んだ
- 書くことなくなってソース読むシリーズでお茶を濁した
- JSゲーム製作勉強会に出た
- 函数プログラミングの集いに出た
- RIP Steve Jobs
- YAPCのスピーカーデビュー
- YAPC::ASIA 2011 をレポートした
- Hokkaido.pm のおかげで結婚した
- Allowsの論文読んだ
- #fcsap にお邪魔した
- Hacker Track に書いた
- node.js に触れた
- Scala に触れた
今年は計算論方面にどっぷり染まった1年でしたが、今後はどうするか迷うところです*1。また、来年は大きな変化も訪れる予定です。そんな変化の年を迎えるにあたり、ブログ名もシンプルにしてみました。
それでは皆様、よいお年をお迎え下さい。
*1:機械学習に戻りたいんだけど、勿体ないし面白いしという泥沼orz
[JS][node]Connectのソースを読む(2)
12月 25th
前回の続きで、Connect 1.8.4のソースを読む。今日はミドルウェアから適当に抜粋。残ってるのはミドルウェアだけなので、今日で終わりのつもり(気が向いたら残りも書くかも?)。
middleware/logger.js
アクセスログを書き込むだけだが、connectのミドルウェアの仕組みではリクエスト完了後に割り込むことができない*1のでhackが必要となる。
具体的に言うと、res.endをラップして終了処理に割り込む。そして、何もせずnextを呼べば、リクエストの完了時に割り込んで処理をすることができる。ただし、immediate オプションを渡した場合はこのhackを行わず、ミドルウェアに処理が移った段階でログを吐く*2。
ログに使える:date、:method などは全てloggerオブジェクトのプロパティにメソッドとして定義されており、req, res, field の3引数を渡すことで値を取り出せる。ログのフォーマットとして文字列を渡すと、これらのメソッドを適宜呼び出すような関数へコンパイルされる。
middleware/errorHandler.js
4引数を持つ唯一のミドルウェア。4引数のミドルウェアはエラーハンドリングのために呼び出される。
~accept.indexOf の形式が多用されているが、ビット反転すると-1が0になることを使っていて、文字列が見つからなかった場合にのみfalseとなる。
内部はAcceptヘッダを見てレスポンスをhtml、json、text に分けてスタックを出力するだけの簡単な処理。
utils.pause, resume
ミドルウェアから使われているutils.js 内の関数。任意のObjectについてpauseすると、以後のdataイベントとonイベントがキャッシュされる。キャッシュされたイベントはresumeで再び元のObjectへ渡される。
ミドルウェアから非同期で後続のミドルウェアへ処理を渡そうとする場合は、このメソッドを使う必要がある。そうしないと、後続のミドルウェアがreqからデータを読むためにdataイベントやendイベントを拾おうとしている場合に、それらのミドルウェアがリスナーをしかける前に発生したdataやendのイベントが全て捨てられてしまう。
middleware/basicAuth.js
BASIC認証の実装。Authorization ヘッダがあって認証が成功していればreq.remoteUserへユーザ名をセット、そうでなければ401ステータスを返して認証を促す、というのを愚直に実装している。
basicAuth()の引数の取り方は3パターンで、「user, pass, realm」「cb(user, pass), realm」「cb(user, pass, cb(err, user)), realm」の3通り。最後のパターンは非同期で認証を行うパターンで、認証が完了したらcbへエラー、またはユーザ名を返せばよい。
middleware/router.js
Sinatraライクのルータの実現。ミドルウェアの中でソースは一番行数が多い。
router関数の中で、まずDSLを実現するためにgetやらpostやらのメソッドを持つmethodsというオブジェクトを作っている。利用者はこいつのgetやらpostやらへルーチング情報を渡せばいいというスンポー。getやpostには、Sinatraなどと同じようにPATHとハンドラを渡せるが、ハンドラに加えてミドルウェアも任意個指定ができる。
後、ドキュメント化されてないapp.paramって関数が生えていて、こいつを呼ぶとparamsという変数へコールバックを貯められるが、この辺の実装はかなり怪しい。要はルーチングでマッチしたパラメータに前処理するためのコールバックなのだけど、普通の関数の他にcb(req, res, next, val) というミドルウェアっぽい(けど違う)引数をとるコールバックも指定できて、整理されてない感がある(非同期対応が必要なのはDBから値を読むことを想定してるんだろうけど)。
ルーチングの情報はroutesオブジェクトへメソッドごとに分けて保存される。getやらpostを呼んだときの処理を作っているのがgenerateMethodFunction で、ここでは基本的にroutesの中へルーチング情報を詰め込むだけ。PATHの正規表現へのコンパイルはnormalizePath関数が行う。
本丸は内部のrouter(req, res, next)関数でこいつが実際にルーチングをする。match関数によってマッチするルートがあるか調べられ、マッチした場合はキャプチャーした値がfn.params へ保存される*3。
さらに内部にあるparamという関数は、前述のparamを前処理するコールバックを反復的に適用するために再帰呼び出しされる関数。これはcb(req, res, next, val)のシグネチャを持つ前処理関数が非同期呼び出しに対応しているために必要となる。なお、この前処理の最中でnextへエラーとして'route'という文字列を渡すと、このハンドラでの処理を諦めて大域脱出し、後続のルーターのマッチ処理へ戻る。
paramの再帰の最後で、ハンドラと共に指定したミドルウェアを適用するため、さらに内部にあるnextMiddleware という関数による再帰が起こる。ここでもミドルウェアがnextへエラーとして'route'を渡すと大域脱出できる。ここのミドルウェアの適用は自前で処理しているが、app(req, res, nextMiddleware) の形式のものしかサポートしていないため、エラー処理をするfn(err, req, res, nextMiddleware)の形式のミドルウェアを渡しても機能しない。
ここまでを経て、ようやく最終的にユーザがgetやpostへ指定したハンドラがキックされる。ハンドラ内からnextを呼ぶと、次のルーチングの検索へ移る。その必要がない場合はres.endでレスポンスを完了すればよい。
最終的にマッチするルートがなかった場合は、OPTIONSメソッドの場合はAllow:ヘッダ入りのレスポンスをするか、それにも該当しなければ後続のミドルウェアへ処理を渡す。
作成されたrouterミドルウェアには、.remove, .lookup, .match のメソッドが生えており、作成後にルーティングを削除したり、どんなリクエストがマッチするのかテストしたりできる。
[JS][node]Connectのソースを読む(1)
12月 23rd
node.js 使ったことがなかったので読んでみる。今日はコアの部分。
下準備
githubからcloneしてきて、checkout 1.8.4した。masterじゃないので注意*1。
npm install を実行すると依存モジュールがnode_modules/ 以下に入る。そうするとmake test でテストを走らせられるようになる。expressoというのでテストをしてるっぽいが、OS X上だとテストが通らない。2.x 系のコードだとテストは通るっぽい*2のでまあ気にしない。
依存とかは package.json を見れば分かる。
patch.js
node.js の機能へのモンキーパッチが入っている。具体的にはプライベートフィールド_headerSentを露出させるアクセサ、Set-CookieとContent-Typeヘッダ周りの拡張、HTTPヘッダ吐き出し直前に新しいフックの追加など。
util.js
ユーティリティ。特筆すべき点はないと思う。
connect.js
エントリポイント。createServer関数を提供しているが、こいつは単にhttp.Serverやhttps.Serverのコンストラクタを呼んでるだけ。typeof で引数を判定して関数のオーバーロードを実現するのはJSの常套句。
また、middleware の一覧の作成もここで行っている。middleware/直下で拡張子が.jsのファイルを片っ端から記憶する。readdirSync でロードしてるのでブロックするが、起動時なので実害はないはず。ここでは各middleware へのアクセサを作るだけで、ロードは利用時まで遅延して行われる。
http.js
ミドルウェアの機能を実現している心臓部。node.jsのhttp.Serverを継承している。(ドキュメントにはない気がするけど)http.Serverのコンストラクタにはrequestイベントのリスナを渡すことになっており、handleメソッドをリスナとして登録している。
handleの前にまずuseメソッド。ミドルウェア(後述)の他に、http.ServerやServer(handlerメソッドを持つもの)のインスタンスを渡せるよう考慮されている。ミドルウェアは登録順にstackプロパティへ保管される。
で、本丸のhandleメソッド。こいつがリスナとなっており、リクエストが発生するごとに適切なミドルウェアを適用してレスポンスを返す責務を担っている。ただし、通常のリスナはreq, resの2引数だが、このメソッドはoutを含んだ3引数となる。これは、handleメソッド自体もミドルウェアとなっているため。
handleメソッド内の記述を読むと、middleware の仕様が読み取れる。具体的には、err, req, res, nextの4引数をとる関数か、req, res, nextの3(以下)引数をとる関数となる。前者はエラーハンドリング、後者は通常の処理を担当している*3。
middlewareのnextという引数がコールバックとなっていて、この引数を呼び出すと次のミドルウェアへ処理が移る。後続のmiddlewareへ処理を渡さない場合は、nextを呼ばずにres.end を呼んでレスポンスを完了するとよい。
nextはエラーの運搬も担当している。全てのミドルウェアを処理してもレスポンスが返せなかった場合は、next経由でエラーが報告されていれば500、そうでなければ404ステータスとしてレスポンスを返している。
https.js
node.js の https.Server を継承したServerを作る。前述のhttp.js のServerからメソッドをコピーしているので、実質はhttp.jsと同じ。
[perl][math]あなたの圏は大丈夫? – 手続き型言語の裏に潜む罠
12月 22nd
Monads in PerlやAllows in Perlの話では、合成compと恒等射idを以下のように定めた。
sub comp($$) { my ($g, $f) = @_; sub { $g->($f->(@_)) }; } sub id { @_ }
しかし、これは厳密には圏とならない。
合成の結合則 h . (g . f) == (h . g) . f が満たされない
合成によって関数の実行順を定義できるので、副作用があっても結合則は満たされる*1。しかし、関数の構造を Inspection するような機能を使うことで結合則は崩れる。Perlの場合、具体的にはcallerがそれに値する。
以下のfは呼出スタックを2つ戻ってその行数を返す関数だが、合成をかける順番によって入れ子になる関数の個数が違うため、差異が出てしまう。よってテストは失敗する。
use Test::More; sub f { (caller(1))[2] } *g = \ *h = \ my $hg_f = comp(comp(\&h, \&g), \&f); my $h_gf = comp(\&h, comp(\&g, \&f)); is_deeply [$hg_f->()], [$h_gf->()];
恒等射の法則 id . f == f が満たされない
これはPerlの事情。Perlにはコンテキストがあるのだが、今のcompの実装では先行する関数を必ずリストコンテキストで評価してしまうため、コンテキストの変化に追従できない。
以下ではスカラコンテキストでの挙動を比較するテストが失敗する。
use Test::More; sub f { wantarray ? 'LIST' : 'SCALAR' } my $id_f = comp(\&id, \&f); is_deeply [f()], [$id_f->()]; is f(), $id_f->();
結合則と恒等射の法則のテストを通してみる
以下のようにすればテストは通る。
package ComposedSub; use overload '&{}' => sub { my $self = shift; sub { my $wantarray = wantarray; my @result; for (@$self) { @result = $wantarray ? $_->(@result) : (scalar $_->(@result)); } $wantarray ? @result : $result[0]; }; }, fallback => 1; sub new { my ($class, @subs) = @_; bless \@subs => $class; } package main; use Scalar::Util qw/blessed/; sub id { wantarray ? @_ : $_[0] } sub comp($$) { my ($g, $f) = @_; return $g if $f == \ return $f if $g == \ my @subs; for ($f, $g) { if (blessed $_ and $_->isa('ComposedSub')) { push @subs, @$_; } else { push @subs, $_; } } ComposedSub->new(@subs); }
まず(h . g) . f と h . (g . f) が完全に同じ構造になるよう ComposedSub というクラスを導入している。これによって結合則が満たされ、括弧を略して h . g . f と書いても差し支えがなくなる。
また、合成時にid()を無視することで恒等射としての性質を与えている。
が、この実装もそんなによいものではない。例えば、この実装では\&main::id のみが恒等射であり、my $hoge = sub { wantarray ? @_ : $_[0] }; は恒等射ではない別の関数である。しかし、常識的に考えると \&main::id と $hoge はイコールとすべきだろう*2。しかしイコールだとすると、comp($f, \&main::id) ≠ comp($f, $hoge) の結果矛盾してしまってうまく収集がつかない。
そもそも、この実装でcompとidが本当に法則を満たしているのか、完全には保証できていない。まだ穴があるかもしれない。そうなるとイタチごっことなる。
モデルと現実の差異とうまく付き合う
厳密に言えば、直感的に実装しただけではPerlの関数群は圏の性質を満たさない。しかし、「副作用は考えない」「リストコンテキストでのみ評価する」など、自分の考えているモデルに併せて実装時に制約を入れれば十分圏として機能するので、大抵の場合は問題ないはずだ。
逆に言えばモデルに課せられた制約からはみ出すような実装をすると理論的な恩恵は受けられなくなってしまうので、今回の評価時のコンテキストやcallerのように法則を破ってしまうような要素や、法則を満たすために実装時に課さなければならない制約についてはある程度把握しておくべきだろう。
[レポート][perl]今日は Hokkaido.pm#6 の日です
12月 10th
実家に帰るついでにふらっと立ち寄りました(2)。次はHokkaido.pmです。
Carton使ってみた / @aloelight さん
- carton → RubyのBundler を Perlに移植したもの
- carton install
- local::lib にインストールされる
- 依存情報はcarton.lock に書き込まれる
- バージョン指定が可能 → インストール済みのもののアップデートにも必要
- carton.lock から依存情報を取り出してインストール
- carton uninstall
- carton exec
- pluckup などのコマンドの実行
- PATH にlocal/bin も追加
- バージョン的には ALPHA なので自己責任
- 利用例(1) Tweet::ToDelicious
- Makefile.PLでは12個指定していたが、実際は53個のモジュールに依存
- 移行も簡単だった
- 利用例(2) JSON RPC Server
- Makefileでは39個、依存を入れて131個
- OrePANを使うなら、PERL_CARTON_MIRRORを使う (ドキュメントにはまだないかも。内部でPERL_CPANM_OPT は無効にされるのでこっち)
- Carton があまりに簡単すぎて話すことがない・・・!!
- おまけ:プロジェクト環境の構築
- perlbrew install-cpanm, install, create, switch
- cpanm install Carton
- carton install
- OrePANにない外部モジュールに依存しているとうまくいかない → mirror_only をパッチ当てて切ってる
- Q. Macで開発してFreeBSDにアップ?
- A. はい
- 5.14 はいいので、使おう
botのつくりかた / @akiym さん
- botとは
- 自動で色々やってくれる
- cpanm AnySan
- 今回はAdvent Calendarの記事を参考
- Twitter の bot → #hokkaidopm を拾ってRTするbot
- 高校生はIRCをあまり使わない → Skype
- AnySan は Skype に対応してない
- AnySan::Provider:: を作った
- SkypeAPI、Win32::Skype, Net::DBus::Skype
- 全て環境依存 → Skype::Any を作成した
- SkypeでURLの内容を表示するデモ
- まとめ
- AnySan で 簡単に bot を書こう
- Skype::Any 作りたいけどMac対応が・・・
- Q. AnyEvent 対応は?
- A. むずかしそう
Clutch - distributed job system / @nekokak さん
- Job Queue → Q4M、TheSchwartz、Gearman、Qudo、Jonk、ZeroMQ、RabbitMQ
- 「使ってる人?」 → ほとんどなし
- Job Queue と Message Queueの違い → 結果を受けるか否か
- 作ってる人はあまり気にしてないのであまりきにしなくていい
- どういう風なフローで作っているかを紹介する
- きっかけ : daemontools の情報をWEBで見たい
- sudo専用のプロセスを作って、webからはそこにジョブを投げる
- 不満から始まる
- gearmandを立ち上げるのは大げさすぎる
- ZeroMQは仕様が変わるかも・・・
- クライアントが直接listen するのがいい
- 「とにかく考える」
- 仕事で忙しいときなど、風呂などのちょっとした時間に考える
- インタフェースをさっくり書いてみる → インタフェースをベースに開発を進める
- 初期実装にかかった時間 → 電車の帰りの時間
- 設計、実装の仕方は人によって違う → 他人と比べるとわかる
- Clutch
- 簡単なプロトコル
- Data::MessagePack によるシリアライズ
- Storable はPerlのバージョンによる互換性がないことがあるので危険
- 自前でSocketを操作する部分を隠して簡単に
- 中間daemonがいらない。Data::WeightedRoundRobin
- Data::WeightedRoundRobin
- 重み付けをしてラウンドロビンできる
- デモ・・・は、保存場所を忘れたのでなしで
- 分散(distributed)
- 多くのdaemon を借りするためadmin daemon も一応ある(workerのIPを管理する)
- Clutch のデモ
- admin を使った場合のデモ (workerとclient が自IPの代わりにadminをIPを指定)
- やりたいこと
- Adminで死活管理をしたい
- Clientでmulticast リクエスト
- Clientでレスポンスを待たずにジョブキュー的な振る舞い
- Job Queue を作る上で気をつけること
- 保護が必要なジョブか
- RDBMS使うか、lock周り、qps
- 重要なこと → 様々なモジュールを知っていること。できることの幅が広がる
まもなくgithubへ上げて下さるそうです。
mod_perl hacks PHP / @xtetsuji さん
- mod_perlの振り返り
- ApacheモジュールでできることをPerlで書けるようにした
- mod_perl2 のみのお話
- PHP : 非常に色々なところで使われているソフト
- PHP製の成果物が社内にあって、触れないことがある
- PHPに手を加えず、Perlで機能追加したい
- mod_perl でPHP実行の前後に処理を突っ込む
- 処理フェーズ。WEBアプリは PerlResponseHandler
- 今回はPHPに限ったお話
- PHPはレスポンスフェーズ以外では何もしていない(らしい)ので
- 例: PHPのセッション処理を使わずに自前で認証をつける
- Access, Authen, AuthzのHandlerでCookieを読み書きする
- Apache2::AuthCookie 割とメンテされてる
- Output Filter Hacksの使い道
- PHPから独自マークアップを残しておき、Perlで最後に置換する
- i-mode絵文字周りなど
- $f->ctx でフィルタのチェーンの最初化がわかる → Content-Lengthを除く
- チャンク読み
- mod_filter → パイプ処理で置換できる。遅い
- まとめ : PHPは処理が控えめなので、mod_perl で色々突っ込める
- mod_perlの情報がWEBに少なすぎる。
- 日本mod_perl改造計画をしたい。ポータルサイトを作りたい
- 文献: mod_perl2 User's Guide
- PukiWiki にフィルタを噛ませて文字を置換するデモ
循環参照のはなし / @hirataraさん
後でスライドを上げておきます。スライド。
YAPC::Asia Hokkaido 実現に向けて / @onagatani さん
- YAPC Asia Hokkaido をやりたい
- 札幌で開催
- 100人以上参加して欲しい
- 7月前後
- 運営委員を集めて定例会議
- 来月札幌にてキックオフを開催
- @hokkaidopm アカウントにて詳細をアナウンス
- JPA がお金の管理。運営委託。
- 100人はできる? → 北海道他の言語の開発者を呼び込む
- 課題 → 運営事務局、スタッフ、マーケティング
- まとめ: スタッフ募集中! 参加社増の施策!
LT
たのしい記号Perlプログラミング / @sugyan さん
北海道へ雪駄で登場したすぎゃーんさんのLTです。
- Perlでチケットをゲットした!
- 北海道の形の記号プログラム
- 7 symbols program
- 拡張正規表現に文字列を食わせればよい
- 文字は7つの記号から排他的論理和を使って作れる
- Acme::HeptaSymbolize
- 画像から、自動でプログラムの形を作れように拡張
- かわいいアイコンでデモ
困ったときのAcme::* / @koji_magi さん
- Acmeモジュールでお祝い Acme::Omedetou
- おめでとうが画面上に表示される気合い系のAcme::*
- Advent Calendar の Acme Trackに参加しましょう
- まとめ: Hokkaido.pm に参加して嫁を作ろう
GUIアプリに必要な3つのこと - ツール編 / @techno_neko さん
- 人見知りの人こそ、スピーカーになって話しかけてもらう
- 感想、アドバイス、知り合い
- 3位 単純明快
- 2位 キャンセルできる
- 適用せずにキャンセル。長い処理の中断。
- 戻す、やり直す
- 1位 痒いところに手が届く
- ユーザーは成長する → UIを使いこなすと、改善を要求する
- 微調整ができること
- まとめ: 触りたくなるUI、痒い所に手が届く、他にも色々ある
Object::Container::Exporter - lazy programming / @nekokak さん
- Object::Container → シングルトンでオブジェクトを管理してくれる
- Object::Container::Exporter
- import に渡した引数、さらに渡した引数を名前空間にしてnewを呼んでくれる
- use 文が少なくてすむ。
- ここで Data::WeightedRoundRobin のデモが見つかったのでデモ
YAPC::Asia Hokkaido 実現に向けてへの補足(仮) / @charsbar さん
- 海外で色々あるよ
- 7月はOSCON
- 6月はYAPC::NA
- 8月はYAPC::Europe
- 4月はOSDC.TW
[レポート][math]今日は 関数型都市忘年会 の日です
12月 10th
実家に帰るついでにふらっと立ち寄ります。
ってことで、札幌に向かっています。午前中は関数型都市忘年会に出席します。途中で退席予定です。
Arrows in Perl / @hiratara
後でスライド貼っときます。スライド。
はじめての函数型プログラミング / @tadsan さん
- 関数とは f(x) = 3x + 2
- あるxに対して対応する値を返す
- このセッションでの表記は「函数」で統一
- 手続き型の例
- Cの for文 → 条件式が必要
- Pythonのfor文 → イテレータ的
- 言語によって設計思考が違う
- Pythonは 手続き型+オブジェクト指向+函数型
- Haskell は純粋関数型言語
- 静的片付けの仲間は実行速度が速い
- 函数型言語とは、λ計算の概念を論理的基盤
- 函数をお手軽に
- 再帰処理
- 函数型言語 → LISP、ML、
- 手続き型の中の函数型
- Ruby, Python, JavaScript → 反復操作、函数の定義
- JavaScript => function, Ruby => lambda
- python => def と lambda と リスト内包表記
- lambda計算について → (λx. x + 2) 3 みたいなの
- Python でlambda計算
- チャーチ数の例
- RubyやPythonで函数型の考えに触れると、函数型言語に入りやすくなる
- Q. 関数型言語で好きなものはなんですか?
- A. F# と Haskell
- Q. Pythonでmap関数を避けたのはなぜ?
- A. Pythonの作者が使いたがってない。LISP的にしたくない。
- Q. どの函数型言語でもラムダ計算がベース?
- A. はい
- Q. 圏論はどうすればわかるの?
- A. 層圏トポスと清水本の圏論の章が日本語で平易
- Q. 末尾最適化がないと再帰はきつい
- A. はい。関数型言語なら大丈夫
最近書いた、関数型言語と関連する?C++プログラムの紹介/ @h_hiro_ さん
- Ubuntu 11 だとgcc4.5が入る。普通だとgcc4.3しか入らない
- 「与えられた文字列に対して、どの単語が何番目にあるかを示す連想配列を作る」
- 関数型言語では、メモリや実行速度より処理の実現方法を気にする
- C++ではメモリ使用量は重要 → メモリを節約しつつ、関数型言語的な記法
- Boost::split → 記法は簡単になるがコピーしているから却下
- 「fundoshi」"他人のふんどしでスモウをとる"
- fundoshi::string → コピーをせずに部分文字列を表現
- 長さの取り出し、文字列比較、ポインタの取得、など
- 自分で必要な部分のみ
- Ruby に慣れるとC++ はエレガントではない
- 記法にこだわりたい
- boostは頑張ってるっぽい。勉強したい
- 記法に拘るネタ(2)
- ファイルから最小の数値を見つけたい場合、int minimumのような変数を用意する
- 一番小さいものをキープするクラスを作った
- 補則「istream_iterator を使うと、cin をイテレータに変えられる」
ここで退室しました。運営の皆さん、ありがとうございました!