4 ms·
> I'm not sure how this would work with Python or JS. .method().method()?
by aaron-lebo 9y ago
> I'm not sure how this would work with Python or JS.
.method().method()?
- yoavm 9y agoI think the concept of piping is actually more similar to function(function()) than .method().method(), because you're not limited to the scope of your initial object's methods. And the truth is that functionB(functionA()) reads much worse than functionA | functionB , so yeah I agree that this is something that shell scripting languages got right.
- yellowapple 9y agoFor reference, various functional languages do indeed treat something like 'foo |> bar' as equivalent to 'bar(foo)' (I've used this extensively in Elixir, where it's standard practice; I'm pretty sure this is derived from F# and/or Clojure, both of which - IIRC - use the same operator for the same purpose). It's not really perfect parity with what a shell typically offers, though, since a shell's pipeline steps (usually) run in parallel and indefinitely, consuming an input stream and producing an output stream (whether those streams are text, rich objects, audio/video data, or something else entirely). Elixir/Erlang are well-suited to achieving that parity by spinning up processes and using message passing for I/O, but Elixir's pipeline operator doesn't really do that (last I checked).
- michaelmrose 9y agoClojure has threading macros that turn (function(function(function) into (-> function function function) An interesting take on that is a library called swiss arrows that lets you do (-<> (function arg1 <>) (function <> arg2) (function arg1 arg2 <>) Using the <> to indicate where the result of calling one shall be threaded into the next.
- robto 9y agoThat's in the standard library, actually. It's called as->. (as-> value <> (function1 arg1 <>) (function <> arg2) (function arg1 arg2 <>))
- michaelmrose 9y agoFound the old swiss arrows and didn't realize that as-> even existed thank you.
- huntie 9y agoExactly what yoavm said. The pipelining that shell languages do allows for more complex and more arbitrary data transformations. I feel that doing this in Python would be difficult, but I'm not very familiar with it. In scheme you can do something like this: (define (pipe . exprs) (if (null? (cdr exprs)) (car exprs) (apply pipe (cons ((cadr expr) (car expr)) (cddr expr))))) (pipe '(3 4 5) (lambda (x) (map 1+ x))) ;; '(4 5 6)
- andreareina 9y agoWrote something similar in Python, even called it the same! def pipe(init_val, *funcs): """Apply `init_val` to the composition of `funcs` pipe(init, func1, func2, ..., funcn) -> funcn(...(func2(func1(init_val)))) """ return functools.reduce(lambda val, func: func(val), funcs, init_val) Check out clojure's threading macros[1] which extends that to taking forms, where the current value is spliced in as the first or last argument. e.g., with ->> (thread-last): (->> '(3 4 5) (map 1+) (reduce +)) ;; 15 Fits the bill for short functions, and you can still have lambdas for when you really need them. [1] https://clojure.org/guides/threading_macros https://clojure.org/guides/threading_macros
- huntie 9y ago>threading macros Wow that's pretty awesome. I'd been annoyed with needing to use lambdas for this type of thing. I especially like the as-> macro. I need to take the time to explore Scheme macros to see what other useful abstractions they can provide.
- lewisl9029 9y agoThis is object-oriented method chaining. Not the same thing as functional composition (piping is essentially just left-to-right composition), which is what's mentioned in the OP. It's also nowhere near as flexible, because it requires the return value to be responsible for providing a set of APIs for the next method call on every step of the chain, whereas each function in a functional composition can operate on any arbitrary input/output. There's actually a proposal for a pipeline operator in JS that I personally really like: https://github.com/tc39/proposal-pipeline-operator https://github.com/tc39/proposal-pipeline-operator I have no idea if it's getting enough traction to get standardized anytime soon though. In lieu of that, I personally just use Ramda's `pipe` function: http://ramdajs.com/docs/#pipe http://ramdajs.com/docs/#pipe Which accomplishes the same thing, but with a bit more ceremony, and not quite as convenient in a scripting setting.