Arrow型クラスの定義
class Category a => Arrow a where
transform :: (input -> output) -> a input output
primary :: a input output -> a (input, extra) (output, extra)
primary = (||| identity)
auxiliary :: a input output -> a (extra, input) (extra, output)
auxiliary = (identity |||)
(|||) :: a input output -> a input2 output2 -> a (input, input2) (output, output2)
func ||| other = primary func >>> transform switch >>> primary other >>> transform switch
where switch ~(x,y) = (y,x)
(|||&) :: a input output -> a input output2 -> a input (output, output2)
func |||& other = transform (\inp -> (inp,inp)) >>> func ||| other
ArrowはCategory型クラスを継承する型クラスであり、関数のより高次の抽象化を提供します。
- transform :: (input -> output) -> a input output
関数をArrowに変換する関数です。
- primary :: a input output -> a (input, extra) (output, extra)
ペアを受け取り、最初の要素に対してArrowを適用します。
- auxiliary :: a input output -> a (extra, input) (extra, output)
ペアを受け取り、2番目の要素に対してArrowを適用します。
- (|||) :: a input output -> a input2 output2 -> a (input, input2) (output, output2)
2つのArrowを用いて、ペアの各要素に別々に処理を適用します。
- (|||&) :: a input output -> a input output2 -> a input (output, output2)
単一の入力を複製し、2つのArrowで別々に処理してペアを生成します。
Arrow則
transform identity = identity
transform (func >>> other) = transform func >>> transform other
primary (transform func) = transform (primary func)
primary (func >>> other) = primary func >>> primary other
primary func >>> transform fst = transform fst >>> func
primary func >>> transform (identity ||| g) = transform (identity ||| g) >>> primary func
primary (primary func) >>> transform grouping = transform grouping >>> primary func
where
grouping ((a,b),c) = (a,(b,c))
標準関数(->)とArrow
instance Arrow (->) where
transform f = f
(|||) func other ~(x,y) = (func x, other y)
Prelude Control.Arrow> (+3) |||& (*3) $ 4
(7,12)
Prelude Control.Arrow> (+3) ||| (*3) $ (2,4)
(5,12)
Prelude Control.Arrow> (+3) <<< (*3) $ 4
15
Prelude Control.Arrow> (*3) >>> (+3) $ 4
15
Prelude Control.Arrow> primary (*3) (2,4)
(6,4)
Prelude Control.Arrow> auxiliary (*3) (2,4)
(2,12)
Prelude Control.Arrow> transform (*3) 4
12
Kleisli Arrowの実装
newtype Kleisli monad input output = Kleisli { executeKleisli :: input -> monad output }
instance Monad monad => Category (Kleisli monad) where
identity = Kleisli return
(Kleisli func) . (Kleisli other) = Kleisli (\input -> other input >>= func)
instance Monad monad => Arrow (Kleisli monad) where
transform func = Kleisli (return . func)
primary (Kleisli func) = Kleisli (\ ~(input,extra) -> func input >>= \out -> return (out,extra))
auxiliary (Kleisli func) = Kleisli (\ ~(extra,input) -> func input >>= \out -> return (extra,out))
Kleisli monad input outputはモナドを返す関数input -> monad outputをカプセル化します。
monadがモナドであれば、Kleisli monadはCategoryおよびArrowのインスタンスになります。
Prelude Control.Arrow> executeKleisli (Kleisli (\x -> [x * 3]) >>> Kleisli (\x -> [x, -x])) 3
[9,-9]
Prelude Control.Monad> (\x -> [x * 3]) >=> (\x -> [x, -x]) $ 3
[9,-9]
Prelude Control.Arrow> executeKleisli (transform length >>> Kleisli print) [3,3]
2
Arrowに関連する補助関数
identityArrow :: Arrow arrow => arrow input input
identityArrow = transform identity
(^^>>) :: Arrow arrow => (input -> middle) -> arrow middle output -> arrow input output
func ^^>> arrow = transform func >>> arrow
(>>^^) :: Arrow arrow => arrow input middle -> (middle -> output) -> arrow input output
arrow >>^^ func = arrow >>> transform func
(<<^^) :: Arrow arrow => arrow middle output -> (input -> middle) -> arrow input output
arrow <<^^ func = arrow <<< transform func
(^^<<) :: Arrow arrow => (middle -> output) -> arrow input middle -> arrow input output
func ^^<< arrow = transform func <<< arrow
Prelude Control.Arrow> (identityArrow :: Int -> Int) 6
6
Prelude Control.Arrow> executeKleisli (identityArrow :: Kleisli [] Int Int) 6
[6]
Prelude Control.Arrow> executeKleisli (length ^^>> Kleisli print) [3,3]
2
Prelude Control.Arrow> executeKleisli (Kleisli print <<^^ length) [3,3]
2