neverthrow icon indicating copy to clipboard operation
neverthrow copied to clipboard

How to reuse a former value in neverthrow pipeline?

Open eakl opened this issue 1 year ago • 2 comments

Hi, I'm new to neverthrow (and functional programming) and I can't understand how to reuse a former value in a pipeline

function run() {
   return fromPromise(
      getData(),
      () => new Error('error getting data')
   )
   .andThen((fetched) => ok(add(fetched, 5)))
   .andThen((added) => ok(multiply(added, 2)))
   .andThen((multiplied) => ok(substract(multiplied, 3)))
   .andThen((substracted, fetched) => ok(add(substracted, fetched))) // fetched is not accessible here
   .match(
      (value) => value,
      (error) => error
   )
}

eakl avatar Nov 12 '24 14:11 eakl

unfortunately, there is no way to reuse a former value. you basically have 2 options here, either "pause" a pipeline mid-way, unwrap the value you need and then start a new one where later you can refer to it. alternatively you may introduce a more complex value in your result to carry the value you need, the approach is similar to the state monad in haskell

nikita-demin-snkeos avatar Nov 13 '24 20:11 nikita-demin-snkeos

You should be able to make an inner pipeline that keeps fetched in context like this:

function run() {
  return fromPromise(getData(), () => new Error("error getting data"))
    .andThen((fetched) =>
      ok(add(fetched, 5))
        .andThen((added) => ok(multiply(added, 2)))
        .andThen((multiplied) => ok(substract(multiplied, 3)))
        .andThen((substracted, fetched) => ok(add(substracted, fetched))),
    )
    .match(
      (value) => value,
      (error) => error,
    )
}

or you can also keep passing fetched to the next pipeline kind of like React's prop drilling concept:

function run() {
  return fromPromise(getData(), () => new Error("error getting data"))
    .andThen((fetched) =>
      ok(add(fetched, 5)).map((added) => ({ fetched, added })),
    )
    .andThen(({ fetched, added }) =>
      ok(multiply(added, 2)).map((multiplied) => ({ fetched, multiplied })),
    )
    .andThen(({ fetched, multiplied }) =>
      ok(substract(multiplied, 3)).map((substracted) => ({ fetched, substracted })),
    )
    .andThen(({ fetched, substracted }) => ok(add(substracted, fetched)))
    .match(
      (value) => value,
      (error) => error,
    )
}

msheakoski avatar Jan 15 '25 21:01 msheakoski