# Reflecting Code to Syntax (with Arrows)

**URL:** <https://discourse.haskell.org/t/reflecting-code-to-syntax-with-arrows/13646>\
**Category:** Uncategorized\
**Created:** [February 3, 2026, 6:48pm UTC](https://discourse.haskell.org/t/reflecting-code-to-syntax-with-arrows/13646 "2026-02-03T18:48:15Z")\
**Posts on this page:** 7\
**Page:** 2

<div class="post-metadata">

**Author:** ![turion](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/turion/32/989_2.png) [@turion](https://discourse.haskell.org/u/turion)\
**Post date:** [February 6, 2026, 3:09pm UTC](https://discourse.haskell.org/t/reflecting-code-to-syntax-with-arrows/13646/21 "2026-02-06T15:09:32Z")

</div>

I agree, arrows should have a desugaring mode like `ApplicativeDo` where the compiler analyses whether the bound variable isn’t used in a later statement, and then uses `arr` and `***` (or `&&&`) instead of `arr` and `first`. A little bit of `arr` for plumbing is probably unavoidable, but the real benefit IMO is to have `***` instead of `first`, like `<*>` instead of `>>=` in `ApplicativeDo`. I sometimes tinker on something like this in my spare time, but it’s much more complicated than just desugaring with `first`.

---

<div class="post-metadata">

**Author:** ![jaror](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jaror/32/3271_2.png) [@jaror](https://discourse.haskell.org/u/jaror)\
**Post date:** [February 6, 2026, 4:50pm UTC](https://discourse.haskell.org/t/reflecting-code-to-syntax-with-arrows/13646/22 "2026-02-06T16:50:58Z")

</div>

That’s a cool paper! However, they don’t actually seem to say applicatives (idioms) are strictly weaker than arrows. They just say applicatives can be embedded into arrows, but it does not say anything about the other direction.

They do show a program that uses a state arrow which cannot be implemented by the usual state applicative:

```haskell
freshName = get >>> arr (\x -> (x + 1, x)) >>> first put >>> arr snd

```

But using my “higher-order” applicative encoding I am able to implement that:

```haskell
data State a where
  Put :: State Int -> State ()
  Get :: State Int
  Pure :: a -> State a
  Ap :: State (a -> b) -> State a -> State b

instance Functor State where
  fmap f = Ap (Pure f) 
instance Applicative State where
  pure = Pure
  (<*>) = Ap

freshName :: State Int
freshName = Get <* Put ((+ 1) <$> Get)

```

> **(and to show this free syntax does have an implementation)**
>
> ```haskell
> interpret :: State a -> Int -> (a, Int)
> interpret (Put p) s = let (x, _) = interpret p s in ((), x)
> interpret Get s = (s, s)
> interpret (Pure x) s = (x, s)
> interpret (Ap p q) s = let (f, s') = interpret p s
> (x, s'') = interpret q s'
> in (f x, s'')
> 
> ```

Here I used the `Get` operation twice, which just happens to work for this simple program. However, we could generalize the `Put` operation to avoid that:

```haskell
  Put :: (a -> Int) -> State a -> State a

```

```haskell
freshName = snd <$> Put fst ((\x -> (x + 1, x)) <$> Get)

```

---

<div class="post-metadata">

**Author:** ![AriFordsham](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/arifordsham/32/979_2.png) [@AriFordsham](https://discourse.haskell.org/u/AriFordsham)\
**Post date:** [February 8, 2026, 11:51am UTC](https://discourse.haskell.org/t/reflecting-code-to-syntax-with-arrows/13646/23 "2026-02-08T11:51:47Z")

</div>

For completeness, there’s been some recent and not-so-recent chatter on the Arrow/Monad hierarchy question

> **[Exploring Arrows for sequencing effects](https://chrispenner.ca/posts/arrow-effects)**
>
> Monads are \<em\>one\</em\> way to sequence effects, but they're not the
> only way!

> **[Monads are too powerful: The Expressiveness Spectrum](https://chrispenner.ca/posts/expressiveness-spectrum)**
>
> Monads are a useful tool, but what costs do we pay for their expressive
> power?

> **[Arrow's place in the Applicative/Monad hierarchy (12 July 2014)](https://gergo.erdi.hu/blog/2014-07-12-arrow's_place_in_the_applicative_monad_hierarchy/)**

---

<div class="post-metadata">

**Author:** ![turion](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/turion/32/989_2.png) [@turion](https://discourse.haskell.org/u/turion)\
**Post date:** [February 13, 2026, 3:16pm UTC](https://discourse.haskell.org/t/reflecting-code-to-syntax-with-arrows/13646/24 "2026-02-13T15:16:32Z")

</div>

Well yes, but the cost here is that `Put` is higher order. The effect signature of your applicative is different than the signature of the arrow. Although applicative vs. arrow is a bit like apples vs. oranges because arrows are profunctors and not functors.

Oh, I realize I didn’t link the paper I wanted to link!

This is the one:

> **[aeia.pdf](https://homepages.inf.ed.ac.uk/slindley/papers/aeia.pdf)**
>
> 292.22 KB

What I really like about that paper is that it recognises how all these “effectish” structures like applicatives, arrows and monads are also about “dynamic” and “static” scopes, like in a DSL. In the plain Haskell world, we have a static language to build up a program with effects using functors, applicatives, arrows, selectives, monads etc., and the values inside these are the dynamic values that are going to be sent around at runtime. So there really is a staged aspect to this.

The point of the paper is then that monads are completely dynamic, they blur the distinction between these two stages. Applicatives are completely static. Arrows/ArrowChoices (and also selectives, not treated in the paper) cover a middle ground by having _static data flow_, but \_dynamic control flow. That is, you can use dynamic values coming out of an arrow to branch, but not to construct a new arrow.

In that sense, arrows are really strictly between applicatives and monads.

---

<div class="post-metadata">

**Author:** ![danidiaz](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/danidiaz/32/92_2.png) [@danidiaz](https://discourse.haskell.org/u/danidiaz)\
**Post date:** [February 13, 2026, 9:34pm UTC](https://discourse.haskell.org/t/reflecting-code-to-syntax-with-arrows/13646/25 "2026-02-13T21:34:01Z")

</div>

> arrows should have a desugaring mode like `ApplicativeDo`

Could the same be achieved using a `QualifiedProc` extension, analogous to [`QualifiedDo`](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/qualified_do.html)? It could potentially offer more flexibility with the typeclasses that back the notation, perhaps even allowing the use of `Profunctor`.

---

<div class="post-metadata">

**Author:** ![turion](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/turion/32/989_2.png) [@turion](https://discourse.haskell.org/u/turion)\
**Post date:** [February 17, 2026, 3:43pm UTC](https://discourse.haskell.org/t/reflecting-code-to-syntax-with-arrows/13646/26 "2026-02-17T15:43:41Z")

</div>

Yes and no.

First, you cannot straightforwardly reproduce the effects of `ApplicativeDo` with `QualifiedDo`. First, `QualifiedDo` does something very similar like `RebindableSyntax`. It just replaces `>>=` and `pure` etc. with your custom definitions. But it doesn’t change the structure of the desugared `do`-Block, just its building blocks. So `ApplicativeDo` is something quite different (and more complicated) than `QualifiedDo`/`RebindableSyntax` because it really analyses usage and changes the structure of the desugared code.

Now, it’s probably easy to generalise `QualifiedDo` to arrows. Already now, [`RebindableSyntax` supports arrow notation](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/rebindable_syntax.html), but it’s not that useful: The arrow desugaring is very rigid and seemingly has a lot of incidental complexity from tuple packing & unpacking, pre-/postcomposition with certain functions in order to bring everything into the right type signature. I’m not aware of any nontrivial usages of `RebindableSyntax` with arrows, not to the extent to what other have done with monads (like [indexed monads](https://hackage.haskell.org/package/freer-indexed) etc.).

And still, you’re (rightfully) asking whether we can improve the way arrows are desugared. Yes, but it probably takes a bit more than just `QualifiedProc`. We should in the end be able to do e.g. this:

```haskell
procDimap :: Profunctor a => (b -> c) -> (d -> e) -> a c d -> a b e
procDimap f g a = proc b -> do
  d <- a -< f b
  returnA -< g d

```

This should only require `Profunctor` to work, not `Arrow`. But as of now, `Profunctor` is not even a superclass of `Arrow`. So the first step is implementing a hierarchy proposal similar to the Functor-Applicative-Monad proposal: `Arrow` should have `Profunctor` and `CartesianCategory` as superclasses. Then desugaring should be able to detect those simpler cases where these two superclasses are sufficient, similar to how `ApplicativeDo` works.

See:

> **[(Co)Cartesian categories - Control.Category.Cartesian](https://hackage.haskell.org/package/categories-1.0.7/docs/Control-Category-Cartesian.html#t:Cartesian)**
>
> Minimum definition:

> **[Overloaded.Categories](https://hackage.haskell.org/package/overloaded-0.3.1/docs/Overloaded-Categories.html)**

---

<div class="post-metadata">

**Author:** ![turion](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/turion/32/989_2.png) [@turion](https://discourse.haskell.org/u/turion)\
**Post date:** [February 17, 2026, 3:46pm UTC](https://discourse.haskell.org/t/reflecting-code-to-syntax-with-arrows/13646/27 "2026-02-17T15:46:19Z")

</div>

And, to go full circle and come back to what stevan said in the beginning: Oleg Grenrus’ plugin [Overloaded.Categories](https://hackage.haskell.org/package/overloaded-0.3.1/docs/Overloaded-Categories.html) actually achieves that to some extent! The trouble is that it’s a GHC plugin and not part of GHC source code. I believe it was too much effort to keep it working after every GHC update, so it bitrotted and doesn’t work beyond 9.0.

[Previous page](https://discourse.haskell.org/t/reflecting-code-to-syntax-with-arrows/13646.md?page=1)
