- http://d.hatena.ne.jp/propella/20070807/p1 1:基本
- http://d.hatena.ne.jp/propella/20070807/p2 2:並置
- http://d.hatena.ne.jp/propella/20070808/p1 3:選択
-- なんか知らんうちに Arrow 流行ってるようなので試してみる。 -- http://www.cs.chalmers.se/~rjmh/afp-arrows.pdf によると、ポイントフ -- リースタイルに IO を混ぜるのが Arrow だと考えればよいらしい。 import Control.Arrow -- Arrow では高階型を使いまくるので慣れないとちょっと恐ろしく見える。 -- Arrow は Monad と同じくクラスだが、Haskell で言うクラスとは他でいう -- インタフェースの事の事なので、色々な型に与えられた Arrow っぽい性質 -- の事を指す。Arrow ッぽい性質を持つものとしては、関数や Kleisli -- (Monad をラップした物)等がある。自分ですぐ忘れてしまうので何度も書 -- くけど、関数の Arrow とは、関数が Arrow (is-a) なのではなく、関数の -- Arrow っぽさの事を言う。Arrow の演算子 >>> の両辺は同じ種類の Arrow -- じゃないといけない。一番簡単な関数の Arrow で説明する。関数の Arrow -- では >>> を関数合成 . の前後を入れ替えた物として使う。パイプみたい -- とも言う。文字列を空白で切って単語を数えるにはこうする。arr は関数 -- から Arrow を生成するのに使う約束だが、関数をそのまま Arrow として -- 使う時は無くても良い。 wc = arr words >>> arr length -- *Main> wc "Hello, I am Takashi" -- 4 -- 次に、ファイルを読んで文字列を数えるというのをやってみる。二つの IO -- 操作 readFile と print を使う。IO 操作から Arrow を作るには Kleisli -- 型を使う(読み方謎)。「Kleisli なんとか」のように書くとなんとかから -- モナドの Arrow (Kleisli の Arrow)が作成され、「runKleisli なんとか」 -- のように書くとなんとかからモナド(IO 操作) を取り出す事が出来る。 -- main 関数の結果として runKleisli を返すと >>> でつなげたモナドの -- Arrow が実行される。 wcFile = Kleisli readFile >>> arr wc >>> Kleisli print -- *Main> runKleisli wcFile "HowToArrow.hs" -- 125 -- また、分配則があるので次のようにも書けるらしい。 wcFile2 = Kleisli readFile >>> arr (words >>> length) >>> Kleisli print -- *Main> runKleisli wcFile "HowToArrow.hs" -- 125 -- リストにリストモナドがあるように、ストリームファンクションという -- Arrow があって、リスト操作を直列に並べる事が出来る。 newtype SF a b = SF {runSF ::[a]->[b]} instance Arrow SF where arr f = SF (map f) SF f >>> SF g = SF (f >>> g) -- しょうもない例ですが、リストを逆順にして二倍する関数を定義。実際に -- 実行するには runSF でリスト関数を取り出す必要がある。 doubleReverse = SF reverse >>> arr (* 2) -- *Main> runSF doubleReverse [1..5] -- [50,40,30,20,10] -- ここまでは面倒なだけで Arrow の意味が無いような気がするけど、ここか -- ら難しくなるのでアップする。