[Haskell-cafe] [ANN] arrowp-qq: an arrowp refresh

Jose Iborra López pepeiborra at gmail.com
Mon Aug 21 16:05:24 UTC 2017


Dear all,

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.

https://github.com/pepeiborra/arrowp <https://github.com/pepeiborra/arrowp>

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!). 

https://hackage.haskell.org/package/arrowp-qq <https://hackage.haskell.org/package/arrowp-qq>

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
```


Thanks,
Jose Iborra
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20170821/a8edd105/attachment.html>


More information about the Haskell-Cafe mailing list