1

I'm new to functional programming and am trying to implement a multiplication -> addition function using in typescript with rambda.

I want a function that takes three numbers, multiplies two together, then adds the result to the third, like so: f(a, b, c) = a + (b * c). Here is the progress I've made so far:

Imperative style

const f = (a: number, b: number, c: number) => a + b * c;

Functional style

const add = (a: number) => (b: number) => a + b;
const mul = (a: number) => (b: number) => a * b;
const f = (a: number, b: number, c: number) => add(a)(mul(b)(c));

The problem with the above solution is the lack of readability of the function f, which is why I am trying to implement the same with Rambda. What I want to be able to say is something like const f = R.pipe(mul, add);, but I'm not sure how to define the functions add and mul to allow that.

Here is what I tried:

const add = (a: number) => (b: number) => a + b;
const mul = (a: number) => (b: number) => a * b;
const f = R.pipe(mul, add);

And the resulting error:

Argument of type '(a: number) => (b: number) => number' is not assignable to parameter of type '(a: number) => number'.
  Type '(b: number) => number' is not assignable to type 'number'.
Nevermore
  • 318
  • 2
  • 11
  • https://remedajs.com/docs#pipe: pipe takes the data first and then the operations to perform. You have not given any data. – Naitik Mundra Jul 14 '22 at 19:19
  • @NaitikMundra I think that's a different library. I'm using rambda's pipe function https://ramdajs.com/docs/#pipe – Nevermore Jul 14 '22 at 19:26
  • Oh, Sorry, did not realize that. It would probably be prudent to add a link to the library you are using in the question. – Naitik Mundra Jul 14 '22 at 19:32
  • Ah! Just saw your code. Does `(a: number, b: number)` instead of `(a: number) => (b: number)` work? – Naitik Mundra Jul 14 '22 at 19:36
  • @NaitikMundra added a link. So that works if I only change the `mul` function to `const mul = (a: number, b: number) => a * b;`. Now I can call it like so: `console.log(f(2, 3)(4)); // 2 * 3 + 4`. Seem to be getting closer, is there a way to make it so that all three arguments can be passed in at the same time? – Nevermore Jul 14 '22 at 19:45
  • Not in the way you hope. This is because you are passing the arguments to different functions. I write Haskell, not TS, so I will be unable to help you with the code, but what you want to do if you will always put it in the same order is to define f as the following: f takes arguments a,b,c. `f = add( c, mul(a,b)).` – Naitik Mundra Jul 14 '22 at 19:55
  • Fair enough, makes sense, thanks! Out of curiosity, mind sharing how something like this would look like written in Haskell? (if it's not too much trouble!) – Nevermore Jul 14 '22 at 20:06
  • Nope never trouble to write haskell. Here you go(add is already defined in haskell. That is why I am using add'). `add' a b = a+b`. `mul a b = a * b`. Now, you could do: ```f a b c= add c $ a `mul` b```. The `$` gives precedence to argument on right. You could replace it with brackets if you wanted to. Types are inferred in haskell, so I did not bother to write them manually, but it can be done. For eg, `add::Int->Int->Int` means `add` takes 2 Integers and returns an Integer. – Naitik Mundra Jul 14 '22 at 20:16

1 Answers1

2

readability first

Function composition is a technique that works best with unary functions. That's not to say you can't compose binary or ternary functions, it's just that it's probably more trouble than it's worth.

const f = (a, b, c) =>
  add(a, mul(b, c))

That's it, you're done! And the readability is fantastic.

"but mom, I want pipe"

If you insist on using compose (or pipe) you can remove one point by partially applying add and mul -

const g = a => b =>
  compose(add(a), mul(b))

Related Q&A: How to understand curry and function composition in Lodash flow?

Mulan
  • 129,518
  • 31
  • 228
  • 259