packages feed

ap-normalize-0.1.0.0: README.md

# Self-normalizing applicative expressions [![Hackage](https://img.shields.io/hackage/v/ap-normalize.svg)](https://hackage.haskell.org/package/ap-normalize) [![pipeline status](https://gitlab.com/lysxia/ap-normalize/badges/main/pipeline.svg)](https://gitlab.com/lysxia/ap-normalize/-/commits/main)

Normalize applicative expressions
by simplifying intermediate `pure` and `(<$>)` and reassociating `(<*>)`.

This works by transforming the underlying applicative functor into one whose
operations (`pure`, `(<$>)`, `(<*>)`) reassociate themselves by inlining
and beta-reduction.

It relies entirely on GHC's simplifier. No rewrite rules, no Template
Haskell, no plugins.
Only Haskell code with two common extensions: `GADTs` and `RankNTypes`.

## Example

In the following traversal, one of the actions is `pure b`, which
can be simplified in principle, but only assuming the applicative functor
laws. As far as GHC is concerned, `pure`, `(<$>)`, and `(<*>)` are
completely opaque because `f` is abstract, so it cannot simplify this
expression.

```haskell
data Example a = Example a Bool [a] (Example a)

traverseE :: Applicative f => (a -> f b) -> Example a -> f (Example b)
traverseE go (Example a b c d) =
  Example
    <$> go a
    <*> pure b
    <*> traverse go c
    <*> traverseE go d
  -- Total: 1 <$>, 3 <*>
```

Using this library, we can compose actions in a specialized applicative
functor `Aps f`, keeping the code in roughly the same structure.

```haskell
traverseE :: Applicative f => (a -> f b) -> Example a -> f (Example b)
traverseE go (Example a b c d) =
  Example
    <$>^ go a
    <*>  pure b
    <*>^ traverse go c
    <*>^ traverseE go d
    & lowerAps
  -- Total: 1 <$>, 3 <*>
```

GHC simplifies that traversal to the following, using only two
combinators in total.

```haskell
traverseE :: Applicative f => (a -> f b) -> Example a -> f (Example b)
traverseE go (Example a b c d) =
  liftA2 (\a' -> Example a' b)
    (go a)
    (traverse go c)
    <*> traverseE go d
  -- Total: 1 liftA2, 1 <*>
```

For more details see the `ApNormalize` module.

## Related links

The same idea can be applied to monoids and monads.
They are all applications of Cayley's representation theorem.

- [`Endo`][endo] to normalize `(<>)` and `mempty`, in *base*
- [`Codensity`][codensity] to normalize `pure` and `(>>=)`, in *kan-extensions*

[endo]: https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-Monoid.html#t:Endo
[codensity]: https://hackage.haskell.org/package/kan-extensions-5.2/docs/Control-Monad-Codensity.html