Arrowを写経

新しい概念を覚えるには、とりあえず写経して使ってみよう。ということでやってみました。
大体何ができるのかわかったような気がしますが、これがピタっとハマる適用例って何でしょう? 便利で使えそうだとは、何となくもやもや思うのですが、どこで使うべきなのかいまひとつピンときません。うーむ。。。

module Main (main) where

import Control.Arrow

f :: Arrow a => a Int Int
f = arr (+ 1)

g :: Arrow a => a Int Int
g = arr (+ 2)

main :: IO ()
main = do
  print $ f 100 -- => 101
  print $ g 100 -- => 102

  -- 関数fとgを直列に繋ぐ。100 + 1 + 2。
  print $ (f >>> g) 100              -- => 103

  -- 右から左もできる(この場合大して変わらないけど)。
  -- 100 + 1 + 2。
  print $ (f <<< g) 100              -- => 103

  -- 関数fとgを並列にする。タプルになる。(100 + 1, 100 + 2)。
  print $ (f &&& g) 100              -- => (101, 102)

  -- 並列にしたのを両方受け取る。タプルを受ける。(101 + 1, 102 + 2)。
  print $ (f &&& g >>> f *** g) 100  -- => (102, 104)

  -- 並列にしたのを最初のものだけ処理する。
  -- 二番目はそのまま。(101 + 1, 102)。
  print $ (f &&& g >>> first f) 100  -- => (102, 102)

  -- 並列にしたのを二番目のものだけ処理する。
  -- 最初のはそのまま。(101, 102 + 2)。
  print $ (f &&& g >>> second g) 100 -- => (101, 104)

  -- EtherのLeftなら関数f、Rightなら関数gで処理する。
  print $ (f ||| g) (Left  100)      -- => 101
  print $ (f ||| g) (Right 100)      -- => 102

  -- Monadも使える。
  runKleisli (f >>> Kleisli print) 100 -- => 101

参照: