# Arrows
# Function compositions with multiple channels
Arrow
(opens new window) is, vaguely speaking, the class of morphisms that compose like functions, with both serial composition and “parallel composition”. While it is most interesting as a generalisation of functions, the Arrow (->)
instance itself is already quite useful. For instance, the following function:
spaceAround :: Double -> [Double] -> Double
spaceAround x ys = minimum greater - maximum smaller
where (greater, smaller) = partition (>x) ys
can also be written with arrow combinators:
spaceAround x = partition (>x) >>> minimum *** maximum >>> uncurry (-)
This kind of composition can best be visualised with a diagram:
──── minimum ────
╱ * ╲
──── partition (>x) >>> * >>> uncurry (-) ───
╲ * ╱
──── maximum ────
Here,
partition (>x) :: [Double] -> ([Double], [Double])
splits up the flow in two [Double]
channels, whereas
uncurry (-) :: (Double,Double) -> Double
merges two Double
channels.
***
(opens new window) is the parallel† composition operator. It lets maximum
and minimum
operate independently on different channels of the data. For functions, the signature of this operator is (***) :: (b->c) -> (β->γ) -> (b,β)->(c,γ)
†At least in the Hask category (i.e. in the Arrow (->)
instance), f***g
does not actually compute f
and g
in parallel as in, on different threads. This would theoretically be possible, though.