2

I have the following code

export const getPostData = (id: string) =>
  pipe(
    getFullPathFileNameForPosts(`${id}.md`), // IO<string>
    chain(getFileContents), // IO<string>
    chain(getMatter), // IO<matter.GrayMatterFile<string>>
    map(R.pick(['data'])),
    bind('id', () => () => id)
  );

above function getPostData() retun

IO<{
  data: {[key: string]: any};
  id: string;
}>

Now I have to add some fileds in the returned result, let's say content, and the result looks like

IO<{
  data: {[key: string]: any};
  id: string;
  content: string;
}>

I write a new function getContent = (matter: matter.GrayMatterFile<string>) => {...}, Now how to add this function to the combined function getPostData?

The main question I want to ask is how to divide the values into different functions for processing in the combined function.

Because the getFileContents function in chain(getFileContents) needs to read the file, I don't want to read this file twice

cdimitroulas
  • 2,380
  • 1
  • 15
  • 22
levin.li
  • 23
  • 4

1 Answers1

3

You can keep using bind and bindTo to keep all the values you need around until you are done using them.

Since you need a matter.GrayMatterFile as an input for the getContent function, you will need to "keep" that value around for a bit longer.

Here is one possible approach:

import { pipe} from 'fp-ts/lib/function'
import { chain, map, bind, bindTo, IO, of } from 'fp-ts/lib/IO'
import { GrayMatterFile } from 'gray-matter'

declare const getMatter: (fileContents: string) => IO<GrayMatterFile<string>>

declare const getFileContents: (filepath: string) => IO<string>

declare const getFullPathFileNameForPosts: (filename: string) => IO<string>

declare const getContent: (file: GrayMatterFile<string>) => IO<string>

export const getPostData = (id: string) =>
  pipe(
    getFullPathFileNameForPosts(`${id}.md`), // IO<string>
    chain(getFileContents), // IO<string>
    chain(getMatter), // IO<matter.GrayMatterFile<string>>
    bindTo('grayMatterFile'),
    bind('content', ({ grayMatterFile }) => getContent(grayMatterFile)),
    map(({ content, grayMatterFile }) => ({
      content: content,
      data: grayMatterFile.data,
      id
    })),
  );
cdimitroulas
  • 2,380
  • 1
  • 15
  • 22
  • Thank you for helping me a lot! – levin.li May 18 '21 at 12:15
  • There is also the alternative of using `sequenceT(reader)` and treating the argument you're dispatching as the reader's context. `pipe(getArg(), sequenceT(reader)(fnThatTakesArg, fn2ThatTakesArg, fn3ThatTakesArg), ([res1, res2, res3]) => ...` – user1713450 May 23 '21 at 05:10