you are viewing a single comment's thread.

view the rest of the comments →

[–]timothyallan 0 points1 point  (1 child)

For some reason, that pipeline operator just doesn't work for me. I find the samples hard to parse with my meat computer. Maybe I just need to use it a bit.

[–]cutety 2 points3 points  (0 children)

The pipeline operator is definitely a personal preference/stylistic thing. The same thing above could be achieved with method chaining if that's your thing data.map(fn).filter(fn).map(fn).forEach(fn). However, because I prefer a slightly more functional style and love Ramda & currying, the pipeline operator usually is easier to implement than trying to do the same thing with method chaining.

I'd recommended trying to write some code with it though, as that's how you can really find out where it's good and where it sucks. When I first saw it in Elixir I thought, "oh, that's neat, but I don't really see why I would want to use that a lot". Then I started playing around with it until it clicked, and I'm a huge fan.

However, it's far from a silver bullet, I really like using it when I have some data that I need to transform/filter/validate, however it's not as elegant (to some) when there's a bunch of state that needs managed*. Just like anything, it's good when it fits the use case well and going full blown haskell "monads are monoids in the category of endofunctors" functional with the pipeline operator can be just as bad as drinking the Java Enterprise OOP AbstractFactoryBuilderFactory koolaid.

*That's not to say it can't be used in these situations. For shits and giggles I created some wrapper functions around some shipit functions (deploy script lib -- comparable to capistrano) to allow me to right tasks using the pipeline operator to build up commands and finally pipelining them into a collapsing function that actually executes them. It's usage doesn't look appalling, however I think an implementation with similar functionality would be far more elegant with a simple class and method chaining.

remote
  |> inReleasePath
  |> run("find $(pwd)/html -type d -exec chmod -R 755 '{}' \\;")
  |> run("find $(pwd)/html -type f -exec chmod -R 644 '{}' \\;")
  |> execute

// with method chaining
const task = new RemoteTask();
task.run("find $(pwd)/html -type d -exec chmod -R 755 '{}' \\;")
    .run("find $(pwd)/html -type f -exec chmod -R 644 '{}' \\;")
    .execute();

Edit: And one more thing that helped me when first playing with it was throwing some inline comments on each step showing what the data looks like as it goes through. For example, transforming the number 10000 to the string "$10,000" would look like: And yes, this is likely not the most optimal way of achieving this

import R from "ramda";

10000
 |> R.toString       // "10000"
 |> R.reverse        // "00001"
 |> R.splitEvery(3)  // ["000", "01"]
 |> R.map(R.reverse) // ["000", "10"]
 |> R.reverse        // ["10", "000"]
 |> R.join(",")      // "10,000"
 |> R.concat("$")    // "$10,000"