0

I’m looking for something like Record.Do with Record.bind so I can do something like this

function getB: (a:A) => B
function getC: (b: B) => C
function getD: (c: C) => D

type Z = {
  a: A,
  b: B,
  c: C,
  d: D,
}

const getZ = (a: A): Z => pipe(
  R.Do,
  R.bind('a', () => a),
  R.bind('b', () => getB(a)),
  R.bind('c', (bindings) => getC(bindings.b)),
  R.bind('d', (bindings) => getD(bindings.c)),
)

I basically want to construct an object of different types while retaining all the inner objects of different types before applying some transformations on them

Not sure how to go about achieving this. I don’t want to take my types to other domains like Option, Either, IO; I feel like that just adds more code using O.some(s) or E.right(s) or IO.of(s) for transformations that don’t error.

This is the closes I could get

const getZ = (a: A): Z => pipe(
  IO.Do,
  IO.bind('a', () => () => a),
  IO.bind('b', () => () => getB(a)),
  IO.bind('c', (bindings) => () => getC(bindings.b)),
  IO.bind('d', (bindings) => () => getD(bindings.c)),
)()

Manav Chawla
  • 61
  • 2
  • 6

2 Answers2

1

Why not just use the do notation on the Identity module? It's a type without any effects, so it should do what you want: https://gcanti.github.io/fp-ts/modules/Identity.ts.html#do-notation

OlaoluwaM
  • 71
  • 1
  • 2
0

The imperative way to do this would be

const getZ = (a:A): Z => {
   const b = getB(a)
   const c = getC(b)
   const d = getD(c)
   return ({a, b, c, d})
}

More fp-ts, but still kinda imperative?

const getZ = (a: A): Z => pipe(
  a,
  (a) => ({ b: getB(a), a}),
  (bindings) => ({ c: getC(bindings.b), ...bindings })
  (bindings) => ({ d: getD(bindings.c), ...bindings })
)

Still looking for suggestions

Manav Chawla
  • 61
  • 2
  • 6