In case anyone finds it useful, there is a new version of arrowp in Hackage that improves the original with a much needed coat of fresh paint. Notable features include a new parser based on haskell-src-exts, a quasi quoter for arrow syntax, and improved desugaring for static choices.
The package is in Hackage as **arrowp-qq** due to the impossibility to contact with Ross Paterson (Ross, if you are reading this, please send email!).
For those of you reading this and wondering why would you want to use a preprocessor for something that GHC can already do, the short answer is that you probably don’t.
Using the `proc` quasi quoter
---------------------------
```
addA :: Arrow a => a b Int -> a b Int -> a b Int
addA f g = [proc| x -> do
y <- f -< x
z <- g -< x
returnA -< y + z |]
```
Comparison with **arrowp**
-----------------------
**arrowp-qq** extends the original **arrowp** in three dimensions:
1. It replaces the `haskell-src` based parser with one based on `haskell-src-exts`, which handles most of GHC 8.0.2 Haskell syntax.
2. It provides not only a preprocessor but also a quasiquoter, which is a better option in certain cases.
3. It extends the desugaring to handle static conditional expressions (currently only if-then-else). Example:
```
proc inputs -> do
results <- processor -< inputs
if outputResultsArg
then outputSink -< results
else returnA -< ()
returnA -< results
```
The standard **arrowp** (and GHC) desugaring for this code is:
```
= ((processor >>> arr (\ results -> (results, results))) >>>
(first
(arr
(\ results -> if outputResultsArg then Left results else Right ())
>>> (outputSink ||| returnA))
>>> arr (\ (_, results) -> results)))
```
This requires an `ArrowChoice`, but there is a more efficient desugaring which
performs the choice at compile time and thus an `Arrow` suffices:
```
((processor >>> arr (\ results -> (results, results))) >>>
(first
(if outputResultsArg then outputSink else arr (\ results -> ()))
>>> arr (\ (_, results) -> results)))
```
Comparison with **GHC**
-----------------------
The GHC desugarer does not do a very good job of minimizing the number of
`first` calls inserted. In certain `Arrow` instances, this can have a material effect
on performance. Example:
```
trivial = proc inputs -> do
chunked <- chunk -< inputs
results <- process -< chunked
returnA -< results
```
This code ought to desugar to a chain of arrows, and indeed, both arrowp and
arrowp-qq desugar this to:
```
trivial = chunk >>> process
```
However GHC will produce (approximately) the following code:
```
arr(\inputs -> (inputs,inputs)) >>> first chunk >>> first process >>> arr fst
```