Hi! I've been discussing in various contexts how multi-backpassing is quite painful to parse correctly.
Here's an example of multi-backpassing, in case you're not familiar:
bar = \x, func ->
func x (x*2)
foo = \x ->
y, z <- bar x
y + z
# equivalent to:
foo = \x ->
bar x (\y, z -> y + z)
(Note, this is just about multi-backpassing, not single-backpassing or backpassing in general)
Parsing multi-backpassing is difficult because the , can often end up confused for a list, tuple, or record separator if we're parsing anywhere inside one of those - and we end up needing to tip-toe around in the parser to avoid accidentally making the wrong choice. The core problem is _ambiguity_ - and it's not unsolvable, but it does make the parser a lot more challenging to work on.
Anyway - the thing I'd like to propose / get feedback on is _removing_ multi-backpassing, since I've heard it's pretty rare anyway. This would start out with a version of the compiler that emits an error if we detect multi-backpassing and give an appropriate suggestion for fixing (which is always possible, since this is purely syntactic sugar).
Again, this doesn't affect normal "single" backpassing, where you only have a single argument - just y instead of y, z.
Anyone using multi-backpassing on a regular basis? What's your use case? Would you be significantly inconvenienced if that was removed from the language?
I didn't know we could do that currently. I kind of have to really think about it to understand what is happening here.
To check I understand correctly, for this example above, if the second argument to bar was a function that took only a single argument then this would be single-backpassing?
Yeah, but then obviously the callsite would have to be different. This is an equivalent example with single backpassing:
bar = \x, func ->
func (x*2)
foo = \x ->
y <- bar x
y + 1
# equivalent to:
foo = \x ->
bar x (\y -> y + 1)
Personally not a fan. I think it is useful and currently we have a limited set of use cases. As platforms expand, I would expect it to become more common. Of course, if we opt for tuples, it should fix the issue, but many functions may not use tuples by default. Personally, I use backpassing essentially everywhere I can and would prefer not to restrict it.
A simple use case is walking over a dictionary. That has 2 values and is great to use backpassing.
Similarly, any function with an accumulator and element also have 2 inputs.
So the walk type functions (can't always use backpassing with them, but nice when it works out and you can).
Interesting; ok.
As platforms expand, I would expect it to become more common.
@Brendan Hansknecht can you say more about what use cases you're expecting to grow here?
Any task that returns more than one result or in general has a continuation with more than one parameter. Currently we may only have simple functions like Stdin.line which on returns a single string, but the apis easily could expand to more full features functions. Maybe they will always return records of data and that won't be a problem, but this seems like a significant area of API space.
A simple example may be a function that registers a callback for web. It may have a continuation with 3 args, exact url, url params, and body of the request.
Any sort of messaging receiver task may give a key and the message value to the callback.
If a task ever takes a walker style function, it may be generated with a state and value in backpassing (I also have done this personally in roc a number of times when walking lists or dictionaries)
Last updated: Jun 16 2026 at 16:19 UTC