Skip to content

Use Monadic composition to simplify the implementation of DispatchMatchers#127

Merged
soareschen merged 18 commits intomainfrom
monadic-pipe
Jul 15, 2025
Merged

Use Monadic composition to simplify the implementation of DispatchMatchers#127
soareschen merged 18 commits intomainfrom
monadic-pipe

Conversation

@soareschen
Copy link
Collaborator

@soareschen soareschen commented Jul 15, 2025

Summary

This PR introduces basic monadic composition support through the cgp-monad crate. The crate offers the PipeMonadic handler, which performs monadic composition (>>) over the Computer, TryComputer, and Handler components.

The PipeMonadic handler has limited support for monadic composition over a "simple" monadic types, e.g. Result or identity. The monad cannot support generic types, e.g. impl Future<Output=T>, due to Rust not yet supporting impl trait in type aliases (TAIT) rust-lang/rust#63063.

Similarly, monad transformers are not supported, due to the difficulty in threading monadic Futures in the continuation, while still satisfying the lifetime and Send bounds. While it is possible to implement monad transformers excluding support for futures, they are not useful for CGP, due to us needing to support async continuations for the Handler trait.

This means that for now, if you want to compose two monads, you have to manually implement a brand new monad that is a composition of the two. But hopefully this need will be rare, due to Rust already offer compelling alternatives for most of the use cases of monad transformers, such as reader, state, and result.

The main use case of implementing PipeMonadic is to support the use of the Result monad within DispatchMatchers. With this, the implementation of DispatchMatchers becomes simply monadic composition over Result.

In the future, this form of monadic composition will also be useful for non-deterministic computation, such as to support property-based testing.

Implementation Details

The monadic implementation in CGP is not exactly the Monad instance we typically know in Haskell. Instead, each "monadic provider" implements the monadic composition (>>) to compose two providers that implement Computer, TryComputer, and Handler. Essentially, this works similar to monad transformers over identity (Computer), Result (TryComputer), and async + result (Handler).

We mainly choose this approach, as described earlier, because of the existing challenges in representing an unboxed impl Future as a monad. Once TAIT is stabilized in the future, we can revisit the design again, and hopefully able to implement generalized monads in CGP.

@soareschen soareschen merged commit 90b41fa into main Jul 15, 2025
5 checks passed
@soareschen soareschen deleted the monadic-pipe branch July 15, 2025 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant