Yes. The profunctors package gives you exactly the “continuation/CPS for arrows” you’re looking for: the Cayley construction for profunctors.
- Type: newtype Cayley p a b = Cayley (forall r. p b r -> p a r)
- Module: Data.Profunctor.Cayley (in the profunctors package)
Intuition
- Arrows are monoids in the monoidal category of profunctors (Paterson: “Arrows are Monads?” / “Arrows as Monoids”).
- The Cayley construction is the same trick that turns any monoid M into a submonoid of its endomorphisms End(M). For monads, this yields Codensity/ContT. For arrows (monoids in Prof), it yields Cayley p.
- As with Codensity, this CPS form gives you an unconstrained Category/Arrow structure on Cayley p, and you only pay your original constraints when you embed from your “almost arrow” into Cayley p or when you run it back.
How it defers constraints
Suppose p is your “almost arrow” type with constrained primitives (arr', >>>', first', …). You can still work in the unconstrained Arrow Cayley p:
So you can build large arrow expressions in Cayley p without threading the Ord-like constraints everywhere, and only discharge them at the boundary where you inject/extract.
What structure on p do you need?
- To get Arrow on Cayley p you need p to be a Profunctor with Strong (and Choice, Closed, etc. for the corresponding Arrow* classes). These are ordinary, unconstrained class instances on p. If even Profunctor/Strong themselves would need per-index constraints, Haskell’s typeclass system can’t express that; Cayley can’t fix that part. But in many “almost arrow” representations, Profunctor/Strong can be implemented without the troublesome constraints, while arr/>>> cannot.
- You do not need p to be a Category/Arrow to give Cayley p those instances; Category for Cayley p uses function composition on continuations, not composition inside p.
Where to find it
- Data.Profunctor.Cayley (profunctors)
- Closely related: Data.Profunctor.Ran. In fact, Cayley p is Ran p p, the right Kan extension of p along itself.
Category-theory “bonus”
- ContT/Codensity is the right Kan extension Ran f f (for endofunctors), i.e. the Cayley transform for monoids in End(Set).
- Cayley p is the same construction but in the monoidal category of profunctors: Ran p p.
- Both are instances of the general Cayley/Yoneda trick: replace a monoid object by its action on itself, yielding a CPS form that often improves laws/instances and defers constraints.
Pointers
- profunctors: Data.Profunctor.Cayley, Data.Profunctor.Ran, Data.Profunctor.Strong, Data.Profunctor.Choice
- Ross Paterson, “Arrows as Monoidal Functors/Arrows are Monads?” for the monoid-in-profunctors view
In short: Yes—wrap your “almost arrow” p in Cayley p. You get an honest Arrow without carrying your Ord-like constraints everywhere, and those constraints are only required where you embed into or run out of Cayley. This is the arrow-level analogue of the ContT/Codensity trick, arising from the same (right Kan extension/Cayley) construction.