-1

I have a couple of functions that currently are written (in abstract form) like this...

const someFunction = x => f(g(x))(x);

i.e.

  1. pass x into g to get the output.
  2. Then pass that output into f to get a function.
  3. And then pass x into that function.

It feels a bit clunky due to the nested brackets, the real world function names, and multiple uses of x etc...

I've been using lodash/fp and my first thought was _.flow but then I'd still have to pass x into the output of the flow in the end.

Hmm... unless I reverse the order of the parameters in f then I could do...

const someFunction = x => _.flow(g, f(x))(x);

I think this would work as f(x) would pass x into f to get the function out. And then this _.flow(g, f(x))(x) would pass x into g and then pass the output of that into the resulting curried function returned from f.

It's still clunky though. Not entirely happy with it. Is there another more elegant/more readable way of doing it that could be suggested.

Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • _"Would that work?"_ - You could just test it instead of asking us to do it for you – Andreas Mar 12 '21 at 09:24
  • It was more of a rhetorical question to prompt other solutions. I have removed it. I wasn't asking anyone to test it for me. Trigger happy mods closing questions too eagerly. It is still a valid question. – Fogmeister Mar 12 '21 at 09:47
  • 1. Why did you ping me? It requires 3 close votes; 2. _"Is there a nicer way"_ is still not a valid question for SO (imho) – Andreas Mar 12 '21 at 09:54
  • 1
    `_.flow()` is not intended for this case. Create an arrow function and curry it - `const chain = _.curry((f, g, x) => f(g(x))(x))` – Ori Drori Mar 12 '21 at 09:59
  • 3
    Your feeling is right, you are on to something. The `f(g(x)) (x)` pattern is actually an instance of one of the most famous patterns in FP. It is the `chain`/`bind`/`flatmap` of the function type, that is one of the terms that are required for a type to form a monad algebra. The applicative version is `f(x) (g(x))`, which is equivalent to the former due to `flip = f => y => x => f(x) (y)`. However, this doesn't help you much, because there is no monad/applicative support in lodash, AFAIK. You need a fantasy-land compliant lib to get the monad machinery. –  Mar 12 '21 at 10:11
  • @scriptum this is awesome! I knew there would be something like this that I could use. Is there a particular library that you would recommend for doing something like this? I opted for lodash because I didn't know any others. Or is the "fantasy-land compliant lib" something that doesn't exist? Thanks – Fogmeister Mar 12 '21 at 10:41
  • @OriDrori I got this working thanks. This is so useful for me! Thanks! I use this pattern all over the place and had to change the ways I wrote a lot of the functions to get around this awkward pattern. Using `chain` like this will allow me to fix all of those cases. Thanks – Fogmeister Mar 12 '21 at 11:19
  • 1
    We usually don't use the raw function type as a monad instance but resort to a wrapped type called `Reader`. Unfortunately there is no lib I'd recommend. The lads of the fantasyland spec have created an [examplary implementation](https://github.com/fantasyland/fantasy-readers) though. The thing is monads are not easy, because you cannot use them standalone. They act systemically, i.e. if you ask for a monad you wind up with lots of monad instances for different types and transformers to compose them and I guess that is not what you want.. –  Mar 12 '21 at 11:21
  • @scriptum ah, ok, makes sense. Thanks very much. – Fogmeister Mar 12 '21 at 11:23
  • @OriDrori or Scriptum if you would like to add an answer I'll accept now. Thanks – Fogmeister Mar 12 '21 at 14:17

1 Answers1

-1

Thanks to the input from @Ori_Drori I created a function...

const chain = _.curry((f, g, x) => f(g(x))(x));

And then my code that started out as...

const myOldFunction = (x) => f(g(x))(x);

turned into...

const myAwesomeNewFunction = chain(f, g);

Which made it much more readable and turned it into a function with a single input which meant I could make it point free and then put it into the rest of my functions really nicely.

Fogmeister
  • 76,236
  • 42
  • 207
  • 306