Splitting this off from:
Sam Mohr said:
We do
mapandmap_err, butmap_okandmap_errwould make more sense
I tried this out in the realworld app and it immediately made things clearer. Here's an example:
params : Request -> List (Str, Str)
params = |req|
req
.path()
.split_first("?")
.map(.after)
.with_default("")
.split_on("&")
.map(|param|
when param.split_first("=") is
Ok({ before, after }) -> (before, after)
Err(NotFound) -> (param, "")
)
params : Request -> List (Str, Str)
params = |req|
req
.path()
.split_first("?")
.map_ok(.after)
.with_default("")
.split_on("&")
.map(|param|
when param.split_first("=") is
Ok({ before, after }) -> (before, after)
Err(NotFound) -> (param, "")
)
in the first version, there are two .map calls, one to Result.map and the other to List.map, but you have to look at the previous call to notice that split_first returns a Result and split_on returns a List
in the second version, every single function call after req.path() is uniquely identifiable without the module name, and req.path() has the variable name to tell you it's a request
I guess you don't know for sure that the map at the end is specifically List.map, but at least I can infer from the name that it's a collection (which is the relevant thing; I know it's being called N times instead of 0-1 times) as opposed to a Result
if we changed split_first and split_on to return tuples, and also did the .get_0() idea to replace .0 accessors, then this could become:
params : Request -> List (Str, Str)
params = |req|
req
.path()
.split_first("?")
.map_ok(.get_1())
.with_default("")
.split_on("&")
.map(|param| param.split_first("=") ?? (param, ""))
Might be a bit soon, but I'm happy to make an Issue for this Result.map -> Result.map_ok and start including it in this round of breaking changes.
It feels good to break things, right? No need to keep stuff working, makes our job easier
works for me!
I'm definitely sold on trying this
I’m all for this. The difference to something like mapping a list is that here you’re only mapping data under certain conditions (if it’s Ok), which it’s good for the name to imply. As opposed to a list mapping, where you are mapping the data unconditionally.
A good explanation!
Do you also want to change Result.map2 to Result.map2_ok (or similar)?
I feel like we don't want to change that. map2 feels fine because we're combining/chaining them. But I'm not sure on that.
map2 probably should be renamed to chain or something similar
That looks a lot nicer in record builder
Though it is less searchable so :shrug:
How about Result.combine? -- I like chain too
What I like about chain is I think it tells me more about what it's doing and why I would use it. I feel like map2 is less friendly for anyone not already familiar with FP.
A better name might also be some sort of join. Cause it takes 2 results and joins them into 1, but map2 is definitely a traditional name
My concern with naming it something completely different than Result.map_ok would make it appear that it does something completely different when the only difference is that the given mapping function takes 2 args rather than only 1. Further, a name like chain (from my limited exposure to other FP langs/libs) seems more akin to bind/flat_map, but please do correct me if I'm off here.
Yeah, chain really only looks good in record builder apis and is not really meaningful elsewhere.
Could call that out in the name and just call it Result.build
How about Result.lift2?
Last updated: Jun 16 2026 at 16:19 UTC