Hacker News new | ask | show | jobs
by kccqzy 2612 days ago
This code

    fn some_wlroots_callback(output_handle: OutputHandle,
                             surface_handle: SurfaceHandle) {
        output_handle.run(|output| {
            surface_handle.run(|surface| {
                // maybe some more nested layers...
            }).unwrap()
        }).unwrap()
    }
is just screaming continuation monad. You see the same code pattern in early Node.js code (sometimes leading to callback hell). In the JavaScript world, the problem was solved using Promises, and then async/await syntax. But more fundamentally, this is an instance of the continuation monad at work.

The continuation monad transformer is defined as

    newtype ContT r m a = ContT { runContT :: (a -> m r) -> m r }
and is nothing more than just a function that takes a callback. If this were Haskell, one could just write

    stuff = runContT $ do
      output <- ContT (run outputHandle)
      surface <- ContT (run surfaceHandle)
      -- and then maybe some more nested layers
      -- etc
Granted, continuation code can easily be misused to produce an incomprehensible mess in Haskell (its full generality can be compared with goto), but with Rust's FnOnce trait, the scope for misuse is considerably reduced.
1 comments

JavaScript and Haskell get to enjoy the productivity of using a tracing GC though.
This doesn't really have much to do with the runtime. Certainly with a GC, programming would be easier, but I'm really talking about abstractions within the language. Rust already has language-integrated support for the Result monad. Rust doesn't have a general `do` syntax, but it has `?` which has made programming with the Result monad much easier. Can we think about the continuation monad and arrive at a new syntax that can ease this style of programming?
i don't really know Rust apart from some curious onlooking, but afaik expressing monads (i.e. the Monad typeclass) in Rust is tricky – something to do with the lifetimes of closures and the objects they close over, i think. ([Idiomatic Monads in Rust] probably touches on that). it might be possible to just build it into the language a la Result or async/await though.

[Idiomatic Monads in Rust] https://varkor.github.io/blog/2019/03/28/idiomatic-monads-in...

It has, because for some of those workflows the borrow checker gets in the way.