Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Result.fromArrayMap #99

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

jmagaram
Copy link
Contributor

@jmagaram jmagaram commented Mar 13, 2023

Creating a new PR for this.

Personally I have run into situations where I have a list of options or a list of results and it kind of hurts my brain figuring out how to "invert/transpose" it. So this PR converts an array<result<'ok,'err>> to a result<array<'ok>,'err>. Among functional programming nerds I found out this is traverse and sequence. The F# article explains these concepts. There are flavors of this kind of function where you get all the errors, which seems less useful. I think the terms "sequence" and "traverse" are a bit technical and prefer the terms I used - fromArrayMap and fromArray. I think this is a good function to have eventually. For completeness we'd want to think through versions for lists and options. Transforming an array<option<'a>> to an option<array<'a>> is handy. And definitely transforming one option to one result and vice versa is useful.

https://fsharpforfunandprofit.com/posts/elevated-world-4/#traverse
https://gcanti.github.io/fp-ts/modules/Traversable.ts.html
https://stackoverflow.com/questions/50789065/turn-list-of-result-into-result-of-list-inside-a-computation-expression

fp-ts and Haskell and other tools for functional programming with type classes let you do this kind of thing. F# doesn't have this. The Rust standard library lets you transform a result of an option into an option of a result.

@glennsl proposed this implementation but acknowledged he hadn't tested it.

@new external makeUninitializedUnsafe: int => array<'a> = "Array"

let fromArrayWith2 = (xs, f) => {
  let oks = makeUninitializedUnsafe(xs->Array.length)

  let rec loop = i =>
    if i >= xs->Array.length {
      Ok(oks)
    } else {
      switch xs->Array.getUnsafe(i)->f {
      | Ok(x) =>
        oks->Array.setUnsafe(i, x)
        loop(i + 1)
      | Error(_) as err => err
      }
    }

  loop(0)
}

@jmagaram jmagaram changed the title Result.fromArrayMap cleaned up a bit Result.fromArrayMap Mar 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant