-2

I have couple of functions, first of which is "expensive" getter:

function getter() {
    return {
      a: "foo",
      b: "bar",
      c: "should be intentionally skipped"
    }
}

Second is transformer, which has a requirement to stay in strictly functional form:

const transformer = x => [getter().a+x, getter().b+x]

Issue is that here are 2 expensive getter calls.

How can I call getter only once, keeping it in fp-form syntax (I particularly mean - without using var, const, let and return inside transformer)?

In other words, what is js fp equivalent of transformer function:

const transformer = (x) => {
    const cached = getter()
    return [cached.a+x, cached.b+x]
}

console.log(f("_test"))

output:

[ 'foo_test', 'bar_test' ]
xakepp35
  • 2,878
  • 7
  • 26
  • 54

2 Answers2

1

keeping it in fp-form syntax - I particularly mean, without using var, const, let and return inside transformer

That is not what functional programming means, not even purely functional programming. You should avoid side effects and keep functions pure so that you gain referential transparency to help understanding the code. It does not mean that you should avoid introducing names in your program. Using const is totally fine! You even use it to declare const transformer.

If you absolutely want to avoid such statements and basically emulate let expressions, you can do

const transformer = x =>
  (cached =>
    [cached.a+x, cached.b+x]
  )( getter() );

And of course, if getter is a pure function, there's no reason to run it every time transformer is called. So just hoist it outside the function body:

const cached = getter();
const transformer = x => [cached.a+x, cached.b+x];
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • "Emulate let expressions with function call" - Excellent wording and awesome solution. Thanks. – xakepp35 Jul 22 '22 at 08:06
  • Functional - I meaned particularily not imperative, where you have 2 separate statememts and you separate them with `;` -imo its non functional, but imperative programming style. As we may see, memoizing in fp is done with closure arguments in funbtional programming style, and with const/let/var in imperative – xakepp35 Jul 22 '22 at 08:13
  • @xakepp35 Given JS is a strictly evaluated functional programming language, you always have some order anyway, whether you use `;` or not. You could even come up with a helper function `pipe = (x, f) => f(x)` that lets you write `pipe(getter(), cached => [cached.a+x, cached.b+x])`, it's exactly the same thing as `const`, nothing imperative about that. Don't make your code unreadable by putting arbitrary restrictions on it. – Bergi Jul 22 '22 at 12:23
0

edit the question has been amended operate on a subset of keys in the computationally expensive object.

This amended answer uses Object.entries() to gather keys and values. Before transforming values, the entries are filtered to include only the desired keys...

function getter() {
  return {
    a: "foo",
    b: "bar",
    c: "should be intentionally skipped"
  }
}

const transformer = x => {
  return Object.entries(getter())
    .filter(([k, v]) => ['a', 'b'].includes(k))
    .map(([k, v]) => v + x);
}

console.log(transformer(" plus x"));
danh
  • 62,181
  • 10
  • 95
  • 136
  • Thanks for your input.Sometimes its hard to create a good example of what you need. A real "getter" in my problem gets much more data, its a big object, but in the end i need only 2-3 values from it. I was actually thinking of running reduce on it, but it does not looks like a very clean syntax.. `key=="a"?append with a+x:key=="b"?append with b:return array unchanged` and it also leaves question open - keys are keys, and values are values... – xakepp35 Jul 21 '22 at 08:05
  • @xakepp35, edited to *filter* keys. – danh Jul 21 '22 at 14:18