Either-like error handling in pipelines

Hi all!

This is my first post, so in the beginning, let me thank you for the awesome language!

I try to find out, what would be the best and idiomatic way to compose functions that can fail, in a lazy manner. I would like to end up with an Error, or with a result.
In my current projects, I am using an awesome fp-ts library, and this is a way I would write this kind of logic:
import * as E from ‘fp-ts/Either’
import { pipe } from ‘fp-ts/lib/function’

const f1 = (input: string):E.Either<Error, string> => {
    return E.right(input)
}

const f2 = (input: string):E.Either<Error, string> => {
    return E.right(input)
}


const f3 = (input: string):E.Either<Error, string> => {
    return E.right(input)
}

const composed = pipe(
    "hello",
    f1,
    E.chain(res => f2(res)),
    E.chain(res => f3(res))
) 

Should I implement Either in rescript and use it in the same way? Or should I use other approaches?

Thanks for your thoughts!

Rescript already ships with a Result type that should get you pretty far, and you can define additional functions to manipulate Results if you need them.

1 Like

Thanks, @benadamstyles! I missed the Result type :no_mouth:
So rescript version of my example could look like this:
let f1 = x => {
switch true {
| true => Belt.Result.Ok(x)
| false => Belt.Result.Error(“error from function 1”)
}
}

let f2 = x => {
  switch true {
  | true => Belt.Result.Ok(x)
  | false => Belt.Result.Error("error from function 2")
  }
}

let f3 = x => {
  switch true {
  | true => Belt.Result.Ok(x)
  | false => Belt.Result.Error("error from function 3")
  }
}

let composed = "hello"->f1->Belt.Result.flatMap(f2)->Belt.Result.flatMap(f3)

The result type is already available in the global scope, so as long as you don’t define any variant constructors that collide with Ok and Error, you can just do:

switch true {
  | true => Ok("hi")
  | false => Error("uh oh")
}

(result is an alias to Belt.Result.t)

3 Likes