arrowp-qq: A preprocessor and quasiquoter for translating arrow notation

[ development, library, program ] [ Propose Tags ]

A suite of preprocessor and quasiquoter to desugar arrow notation built on top of Ross Paterson's arrowp and the venerable haskell-src-exts.


[Skip to Readme]
Versions [faq] 0.1, 0.1.1, 0.2, 0.2.0.1, 0.2.1, 0.2.1.1, 0.3.0
Dependencies arrowp-qq, base (>=4.7 && <5), containers (>=0.6.0 && <0.7), data-default (>=0.7.1 && <0.8), haskell-src-exts (>=1.22.0 && <1.23), haskell-src-exts-util (>=0.2.5 && <0.3), haskell-src-meta (>=0.8.5 && <0.9), NoHoed (>=0.1.1 && <0.2), template-haskell (>=2.14.0 && <2.15), transformers (>=0.5.6 && <0.6), uniplate (>=1.6.12 && <1.7) [details]
License LicenseRef-GPL
Author Jose Iborra <pepeiborra@gmail.com>
Maintainer John 'Ski <riuga@tuta.io>
Category Development
Home page https://github.com/pepeiborra/arrowp
Source repo head: git clone http://github.com/pepeiborra/arrowp
Uploaded by riuga at 2019-12-29T14:40:18Z
Distributions NixOS:0.3.0
Executables arrowp
Downloads 4233 total (21 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Hackage Matrix CI
Docs uploaded by user
Build status unknown [no reports yet]

Modules

[Index] [Quick Jump]

Flags

NameDescriptionDefaultType
debug

Enabled Hoed algorithmic debugging

DisabledManual
testexamples

Build the examples using the preprocessor and quasiquoter

DisabledManual

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainer's Corner

For package maintainers and hackage trustees


Readme for arrowp-qq-0.3.0

[back to package description]

Hackage Stackage Nightly Travis Build Status

arrowp-qq

A preprocessor (aka syntax-desugarer) for arrow notation based on the original arrowp developed by Ross Paterson ross@soi.city.ac.uk.

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. See the semantics section below for more details.

Note: arrowp-qq provides an enhanced superset of the original arrowp's functionality. One should have no reason to install both. Considering arrowp no longer builds under modern versions of GHC and Cabal/Stack, arrowp-qq should clearly be the more optimum package to install.

Both arrowp and arrowp-qq were originally developed during the days when GHC's Arrows extension was not fully mature--a time when proc syntax was not the norm. Of course, recent versions of GHC now support this notation directly, and give better error messages to boot. Unfortunately, GHC's proc notation desugarer is in some cases not as good as it could be. As such, arrowp-qq's quasi-quoter can still be useful in producing slightly more optimized desugaring for performance-critical, arrowized applications.

The modern use cases of arrowp-qq are as follows:

  • Viewing how your proc blocks (roughly) look like after desugaring for debugging/profiling purposes.
    • Via the arrowp executable.
    • NOTE: arrowp-qq is NOT guaranteed to produce the same desugaring as GHC (see limitations & semantics below).
  • Optimizing the performance of your proc blocks via smarter desugaring.
    • Either through the arrowp executable OR (preferably) the provided quasiquoter.

Limitations

The parser cannot handle banana brackets for control operators in arrow notation (the proc keyword in the original paper), due to a limitation in haskell-src-exts. In order to use banana brackets, the recommendation is to fall back to the GHC Arrows parser.

Support for GHC Haskell notation inside arrow blocks is not complete, e.g. multi-way-if and lambda case are unlikely to work as expected. If you run into one of these, please open an issue or vote for an existing one, as I plan to extend the support on demand.

Installation

arrowp-qq is now compatible with Cabal v3's Nix-style local builds & installs:

cabal install arrowp-qq

Usage

Viewing desugared proc syntax

arrowp myfile.hs | less

Optimization

Via the proc quasiquoter

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

Via the arrowp preprocessor

Add the following GHC pragma to the top of the source file:

{-###  OPTIONS -F -pgmF arrowp ### -}

This can be useful for preserving compatibility with vanilla proc notation, at the cost of flexibility; that is to say, all proc blocks within the source file will be desugared via arrowp-qq.

Desugaring Semantics

Static conditional expression optimization

As mentioned previously, arrowp-qq extends the original arrowp's desugaring to handle static conditional expressions. Given:

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

first call optimization

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