Stream: ideas

Topic: List.filterMap as builtin


view this post on Zulip Fletch Canny (Dec 30 2023 at 00:41):

Hi everyone!

I find myself using List.joinMap a lot where a filterMap would be more sensible for both readability and performance. #664 doesn't mention a filterMap, so would this be an idea people would be interested in?

Something like

filterMap : List a, (a -> [Keep b, Drop]) -> List b

view this post on Zulip Brendan Hansknecht (Dec 30 2023 at 01:01):

So map and keep if together in one?

view this post on Zulip Fletch Canny (Dec 30 2023 at 01:11):

Exactly. It's useful when you want to filter based on what the element will be after applying the function. It helps avoid sentinel values and redundant computation. It's essentially List.keepOks but for things which aren't errors. For example:

A: [B U32, C]

withFilterMap =
  List.filterMap [B 0, C, B 1] \a ->
    when a is
      B b -> Keep b
      C -> Drop

withJoinMap =
  List.joinMap [B 0, C, B 1] \a ->
    when a is
      B b -> [b]
      C -> []

if you try rewriting these without joinMap you'll probably see why I use joinMap, and why I want a filterMap.

view this post on Zulip Brendan Hansknecht (Dec 30 2023 at 01:26):

Makes sense

view this post on Zulip Agus Zubiaga (Dec 30 2023 at 01:52):

Hm, why not just use keepOks? It’s the same but with a different tag name

view this post on Zulip Agus Zubiaga (Dec 30 2023 at 01:54):

  List.keepOks [B 0, C, B 1] \a ->
    when a is
      B b -> Ok b
      C -> Err {}

view this post on Zulip Fletch Canny (Dec 30 2023 at 01:57):

Okay that's definitely better than joinMap haha. I will say it doesn't communicate what you're doing as well imo. keepOks means "lets do this function and only keep the ones which don't error", but when using filterMap the idea is just "we're mapping a function and disregarding some along the way" which are isomorphic but linguistically distinct enough to warrant its existence.

view this post on Zulip Agus Zubiaga (Dec 30 2023 at 02:11):

Yeah, that’s a good point. I think of Result as Good/Bad more than Success/Failure, but I get why the latter is the default understanding.

view this post on Zulip Fletch Canny (Dec 30 2023 at 02:17):

Either way I wouldn't say the things you want to drop from the list are either bad nor failures- they're just things you don't want.
It might also be better because you can't accidentally conflict with other types. It would be a lot clearer where my types are wrong if the compiler told me I needed a tag of [Keep a, Drop] rather than [Err {}, Ok a], especially if a is a Result itself, so the compiler would tell you that you want a [Keep [Result a e1], Drop] rather than [Err {}, Ok [Ok a, Err e1]], which probably won't be a problem when error messages improve but it's something to think about.

view this post on Zulip Richard Feldman (Dec 30 2023 at 02:55):

yeah I actually originally thought about having Keep and Drop, but I figured people would often want to use it in conjunction with things that return Result, since there are a lot of those, so I went with keepOks instead :sweat_smile:

view this post on Zulip Fletch Canny (Dec 30 2023 at 03:08):

So is the plan to not include filterMap as a builtin?

view this post on Zulip Richard Feldman (Dec 30 2023 at 12:38):

right now I'd say I'm not convinced we should add a function that does the same thing as a current function except the tags have different names.

A downside of having both is that it would create stylistic debates about which would be more appropriate to use in a given piece of code, and I think that's not a good use of people's time. :big_smile:

view this post on Zulip Fletch Canny (Dec 30 2023 at 12:41):

I suppose that's a driving force behind a lot of the language haha. At least it's good to know that keepOks is basically the same thing, which hadn't really occured to me until this thread.

view this post on Zulip Kevin Gillette (Dec 31 2023 at 04:43):

Regarding List.keepOks, it sounds like there's a great opportunity for reinforcing in the tutorial that there are no truly special tags, and that functions that are result-focused can be purposed for intermediate processing as well.

view this post on Zulip Kevin Gillette (Dec 31 2023 at 04:44):

or perhaps that'd be a "Thinking in Roc" advanced topics doc


Last updated: Jun 16 2026 at 16:19 UTC