I have found that arrows in Haskell are far simpler than they might appear based on the literature. They are simply abstractions of functions.

To see how this is practically useful, consider that you have a bunch of
functions you want to compose, where some of them are pure and some are
monadic. For example, `f :: a -> b`

, `g :: b -> m1 c`

, and `h :: c -> m2 d`

.

Knowing each of the types involved, I could build a composition by hand, but
the output type of the composition would have to reflect the intermediate
monad types (in the above case, `m1 (m2 d)`

). What if I just wanted to treat
the functions as if they were just `a -> b`

, `b -> c`

, and `c -> d`

? That is,
I want to abstract away the presence of monads and reason only about the
underlying types. I can use arrows to do exactly this.

Here is an arrow which abstracts away the presence of `IO`

for functions in
the `IO`

monad, such that I can compose them with pure functions *without the
user needing to know that IO is involved*. We start by defining an

`IOArrow`

to wrap `IO`

functions:```
data IOArrow a b = IOArrow { runIOArrow :: a -> IO b }
instance Category IOArrow where
id = IOArrow return
IOArrow f . IOArrow g = IOArrow $ f <=< g
instance Arrow IOArrow where
arr f = IOArrow $ return . f
first (IOArrow f) = IOArrow $ \(a, c) -> do
x <- f a
return (x, c)
```

Then I make some simple functions I want to compose:

```
foo :: Int -> String
foo = show
bar :: String -> IO Int
bar = return . read
```

And use them:

```
main :: IO ()
main = do
let f = arr (++ "!") . arr foo . IOArrow bar . arr id
result <- runIOArrow f "123"
putStrLn result
```

Here I am calling `IOArrow`

and `runIOArrow`

, but if I were passing these
arrows around in a library of polymorphic functions, they would only need to
accept arguments of type “Arrow a => a b c”. None of the library code would
need to be made aware that a monad was involved. Only the creator and end
user of the arrow needs to know.

Generalizing `IOArrow`

to work for functions in any `Monad`

is called the
“Kleisli arrow”, and there is already a built-in arrow for doing just that:

```
main :: IO ()
main = do
let g = arr (++ "!") . arr foo . Kleisli bar . arr id
result <- runKleisli g "123"
putStrLn result
```

You could of course also use arrow composition operators, and `proc`

syntax,
to make it a little clearer that arrows are involved:

```
arrowUser :: Arrow a => a String String -> a String String
arrowUser f = proc x -> do
y <- f -< x
returnA -< y
main :: IO ()
main = do
let h = arr (++ "!")
<<< arr foo
<<< Kleisli bar
<<< arr id
result <- runKleisli (arrowUser h) "123"
putStrLn result
```

Here it should be clear that although `main`

knows the `IO`

monad is involved,
`arrowUser`

does not. There would be no way of “hiding” `IO`

from `arrowUser`

without arrows — not without resorting to `unsafePerformIO`

to turn the
intermediate monadic value back into a pure one (and thus losing that context
forever). For example:

```
arrowUser' :: (String -> String) -> String -> String
arrowUser' f x = f x
main' :: IO ()
main' = do
let h = (++ "!") . foo . unsafePerformIO . bar . id
result = arrowUser' h "123"
putStrLn result
```

Try writing that without `unsafePerformIO`

, and without `arrowUser'`

having to
deal with any `Monad`

type arguments.

This seems more compelling then other intros to arrows iIve seen, but kind of suggests that arrows are mainly useful for library writers but i guess that may not quite the whole story?

Would also be nice to see where other Control.Arrow operations fit in

The arrow operations, like `&&&` and `|||` are really about observing intermediate results between arrows without breaking the arrow abstractions. This is how `proc` notation is implemented behind the scenes, if you were to desugar it.