Subscribed unsubscribe Subscribe Subscribe

HIMA' #1: iteratee I/O勉強会

Haskell HIMA'

Boost.勉強会 #2と同じ日に同じ場所で、iteratee I/O勉強会を開きました。

id:tanakhさんによるIteratee: Teaching an Old Fold New Tricksのまとめ記事を読み上げながら、参加者が気になったところに都度つっこみを入れるという形式で進めました。当初の予定ではこのドキュメントをベースに様々な話題について取り上げるつもりでしたが、iteratee自体が難しいことや思いの外つっこみが盛り上がったこともあり、ほぼ上のドキュメントのみで時間切れとなりました。

また今回参加できなかった方々のために詳細なログを取ろうと思っていたのですが、議論について行くのが精一杯で早々に諦めました。すみません。> 不参加だった方々

今後の勉強会について

今回はiteratee I/Oについての単発の勉強会でしたが、これを毎月開催の勉強会にします。以前HIMAというオンラインミーティングがあったので、HIMA'(ひまぷらいむ)と改め、月一くらいのペースで(オフラインで)開催します。

HIMA'の目標はHaskell(や関数プログラミング)に関連するトピックについて活発に議論する場として機能することを目指しています。例えば、

  • The Monad.ReaderやFunctional Pearls、その他の論文などから面白いトピックを取り上げて議論
  • 面白いものを作ってみたから見て!みたいな話
  • 面白いライブラリの紹介や応用

などができると良いかなと思います。

テーマは毎度勉強会の最後に決めます。形式は自由ですが、今回のように発表担当を決め、参加者は発表に対してつっこみをいれて議論するのが良いかもしれません。次回はぐっと実際寄りになって、id:nobsunさんとid:kazu_yamamotoさんによる「darcs / gitの比較」を10/24(日)に予定しています。

大まかな議論の内容

以下簡単にですが、僕の理解・記憶しているところを書いておきます。

  • lazy I/Oの問題点
    • composableでない
      • これを簡潔に示す例が欲しい
    • 安全性に欠ける
      • 例外がI/Oと直接関係ないところで起こってキャッチできないことがある
      • bracketを使ってもHandleを返すことができる
        • リージョン推論を使えばHandleを漏らさないことを型レベルで保証できる
    • あとはgetContents系のアクションはreadを途中で止められない(EOFが来ないとHandleを閉じられない)とか
    • enumerator vs. cursorの議論
  • iterateeとenumeratorとrunの関係
    • HyenaのIterateeがわかりやすい
    • foldl f z xsのアナロジーで考えると
      • foldlがenumerator相当。ただしDoneならすぐに終了する。
      • fがiteratee相当。ただしearly terminationのためにDone/Contというラベルを持つ。
      • xsはHandleやByteStringなどのenumerateされる対象
      • runは初期値z(EOF)を与えてenumeratorを走らせる
  • StreamG elにあるEmptyは何故必要か
    • この例ではストリームはチャンクではなく単一のようそのため、空要素を示すために必要。
    • 使用例から言うとiterateeをmonadicに繋いだとき、前のiterateeが要素を消費したか否かを示すために使う。
      • Done a Emptyなら消費済み。Done a (El el)なら消費してない。cf. headとpeek
      • チャンクの場合は単純に消費した分をdropしたチャンクを返す
  • runの定義
    • run'でiterateeにEOFを与えた結果がDoneになっているかどうかチェックしているが、そもそもEOFを与えられたときにDoneにならないiterateeを書けてしまうのは良いのか
    • runでチェックするべきかiteratee側でチェックすべきかのデザインチョイスがある
  • 各iterateeの定義
    • iterateeがDoneになったときストリームを返す必要はあるのか?True or Falseでも良いのでは?
      • 扱うストリームがチャンクになるとBoolではまずいと思う
  • iterateeはオートマトンである
  • iterateeはmonad
    • Done x' _ -> Done x' strのところでRHSはstrでいいの?
      • m >>= \x -> f xのときf xがDoneになるならストリームは消費してないのでstrでよいはず(という話だっけ?)
      • OlegさんのIteratee.hsに解説があった
  • ifMが欲しい
    • monadicなコンテキストでif then elseが使いにくい
    • Monad m => m a -> m a -> Bool -> m aがあると便利
    • mBool >>= onChoice mTrue mFalse みたいに使える
  • FunctorのfmapはliftMでいいんじゃないの?
  • monadicなiteratee
    • i `enumPair` i' と (,) <$> i <*> i'は異なる
    • 前者は並行で後者は逐次的
  • enumeratee
    • なんでこんなに複雑なんだ
    • convStreamではmany-to-oneとかmany-to-noneはできないよね
  • 別の実装
    • iteratee-0.2で使われている、より明示的にストリームを受け渡しするタイプ
      • 何が嬉しいのか?
      • OlegさんのIterateeM.hsに比較が書いてあった。
      • あまり嬉しくないようだが、いまいちよくわからないので後で調べる。
    • CPSな実装
      • テクニカルには、forall r.なのはLHSにrが出てないのにRHSにrが出てくるから。
      • 意味的にはrの型を固定したくないからなんだろうけど、理解できてない。後で調べる。
      • 詳しい解説誰か求む

iteratee I/Oはまだ整理されてない(もしくはOlegさんの頭の中でしか整理されてない)考え方という印象でした。たぶんより適切なモデルと実装が必要なんじゃないかなと思います。

懇親会では、@pirapiraさんと@masahiro_sakaiさんが二人で議論を始めると、日本語なのにほとんど助詞くらいしか理解できなくなる感じがとても素敵でした。僕も少しは理解できるように頑張りたいです。