DEV Community

loading...

Discussion on: A simple explanation of functional pipe in JavaScript

Collapse
dmitriz profile image
Dmitri Zaitsev

It looks like the pipeline in general provides a really convenient and reusable syntax, also battle-proof from decades of use in Unix and other languages. But the pipeline proposal seems to get stale with multiple disagreements and can take years to complete.

The pipeWith function keeps the linear flow but mixes arguments with functions inside its arguments and requires to begin with array:

pipeWith([1, 2, 3, 4, 5], odds, double, log);
Enter fullscreen mode Exit fullscreen mode

Why not instead use a curried pipeline function with identical functionality:

pipeline(1, 2, 3, 4, 5)(odds, double, log)
Enter fullscreen mode Exit fullscreen mode

Among advantages: no need to wrap arguments in an array and typing the comma is quicker than "|>" that requires 2 Shift + 2 keys (4 in total vs 1 for the comma)?

I have been searching for cleanest and most reusable patterns to write and compose Continuation-Passing-Style functions and this pipeline curried function seems to do "the best job", but I'd be curious to put this claim to test and hear other thoughts.

Collapse
puiutucutu profile image
puiu

Not data last.

Collapse
redbar0n profile image
Magne

Why is data last important? If the function composition grows (multi-line), it can be annoying to go to the end just to see what is passed in at the beginning. Chronological ordering is more readable. If it doesn't pose a clear disadvantage, I don't see why not use it.

Thread Thread
misterjones profile image
mister. jones

From what I understand of functional programming, currying typically uses a data-last approach.

It's nice, because it allows you to create functions from composed functions. So, yes, if you're piping a lot of functions into your pipeline, it could be annoying to have to find the end-of-the-line to check what data is actually being piped through. But, I'd argue that if you're piping that many functions through, you should consider making it into a named function anyway, so that readers don't have to parse through every step to understand what it's ultimately doing.

Manuel Romero already posted a slugify function (above) as an example, so I'll riff on that:

const pipe = (...fns) => x => fns.reduce((y, f) => f(y), x);

const toLowerCase = str => str.toLowerCase()
const split = separator => str => str.split(separator)
const join = separator => arr => arr.join(separator)

const slugify = pipe(
  String,
  toLowerCase,
  split(' '),
  join('-')
)

fooBarSlug = slugify('Foo Bar Fizz Buzz')
console.log(fooBarSlug)  // foo-bar-fizz-buzz
Enter fullscreen mode Exit fullscreen mode
Collapse
thiagorb profile image
Thiago Romão Barcala • Edited

From one side it is sad to have to wait so long for this improvement, but from the other side it is better to wait than to have a modification in the language syntax that doesn’t work well in the future.

Your efforts to find the perfect syntax are definitely valuable, but I think it requires a lot of analysis of the consequences to avoid superficial argumentation. Removing the need to wrap arguments in an array doesn’t necessarily makes things easier, because it is more likely that the argument being piped will be already coming as a variable from somewhere else. So we would rarely construct arrays to pipe, but pipe some existing array. And in this case you would need to spread the array to be able to use it in the pipe. Besides that, the pipeline operator can be used with anything, not only arrays. It is just a different way of writing nested function calls.

Also, the amount of keys pressed to type the code is not that important, because we spend more time reading code than actually typing, so maybe less parentheses is preferable instead of one extra character.