Add full monad transformer support for monadic composition of CGP handlers#129
Merged
soareschen merged 21 commits intomainfrom Jul 18, 2025
Merged
Add full monad transformer support for monadic composition of CGP handlers#129soareschen merged 21 commits intomainfrom
soareschen merged 21 commits intomainfrom
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This is a follow up improvement over #127 to provide full monadic transformer support on handling monadic composition on CGP providers such as
Computerand `Handlers.Compared to the previous PR, we can now make use of a monad transformer stack to compose handlers that return results wrapped in nested monads.
Example
An example use of this is the
OkMonadicTrans<ErrMonadic>monad, which can extract a valueTfrom a nested result typeResult<Result<E1, T>, T>, where the inner success value is placed inErrinstead ofOk. This use case is particularly useful to implement the extensible visitor pattern, where the extraction of a variant returns the remainder inErr, while the successful extraction inOkis short circuited.Implementation Details
Behind the scene, instead of composing two handlers directly, we define a
MonadicBindto lift the inputs of a handler into a monad. It has a Haskell signature that looks like:That is, the argument order of the CGP bind is the inverse of the usual ordering of
(>>=):The main implication is that the CGP monadic bind can work directly with a
Computerthat is in the forma -> m b, and produce a newComputerinstance that is in the formm a -> m b.Another main difference of CGP's monad and Haskell's monad is that the monadic operation is defined outside of the involved type. For example, both
OkMonadicandErrMonadiccan be used to perform monadic bind on theResulttype. This design is intentional, as we also want to eventually support monadic operations on opaque types that implement monadic traits, such asimpl Futureorimpl Iterator. Since these opaque types are all distinct types, we have to make the monadic bind to support arbitrary types that implement the specific traits that we are interested in, without explicitly wrapping them in a monadic type.The
MonadicBindimplementation in CGP also requires explicit support on theHandlercomponent, which has an async function that returns aFuture. Although theFutureitself is monadic, it is currently not possible to name that opaque future as type due to Associated type position impl trait (ATPIT) not yet being stabilized. In other words, it is currently not possible to "downcast" aHandlerinto aComputer, because we can't name the returnedimpl Futureas the associatedOutputtype inComputer.