4 ms·
Your example falls apart when making multiple function calls.
by weliketocode 8y ago
Your example falls apart when making multiple function calls.
- nabla9 8y agoPlease explain.
- Spivak 8y ago64 |> Math.sqrt becomes pipe(64, Math.sqrt) 64 |> Math.sqrt |> Math.sin becomes pipe(pipe(64, Math.sqrt), Math.sin) Assuming pipe was smart and took varags we can make this better. 64 |> Math.sqrt |> Math.sin becomes pipe(64, Math.sqrt, Math.sin)
- Leszek 8y agoI guess you could make pipe variadic: function pipe(val, ...funcs) { for (let f of funcs) val = f(val); } EDIT: seems like I got ninja'd by an edit :)
- nabla9 8y agoJavaScript argument list evaluation is from left to right, right? pipe(64,Math.sqrt,Math.sin) and pipe(pipe(64, Math.sqrt), Math.sin) are equivalent.
- Spivak 8y agoIf you just define a simple function pipe(val, func) => func(val) then they wouldn't be equivalent but you absolutely could define pipe so they would be.
- hajile 8y agoA pipe operator compiles directly into the AST and completely disappears before execution. 64 |> Math.sqrt |> Math.sin Compiles in the AST to Math.sin(Math.sqrt(64)) //curries variables away from functions var realPipe = (a, ...args) => (...initParams) => { var acc = a(...initParams); for (var i = 0; i < args.length; ++i) { acc = args[i](acc) } return acc; } //if first parameter is a function, curry to delay execution //if first param is not a function, curry, but call immediately var pipe = (a, ...args) => (typeof a === "function") ? realPipe(a, ...args) : realPipe(...args)(a) I'd note that this pipe implementation also bleeds its abstraction. JS has first-class functions, but this will never treat a function as data. You must be aware of how it works so if you are passing a function (for example, a getter function), you must manually curry it afterward. This complication is why most pipe implementations don't actually mess with that data attribute part (they just skip to the realPipe implementation), but since the pipe operator can handle it, I figured I'd try to as well to show the issues.
- Spivak 8y agoI see no reason our function form couldn't do the same magic behind the scenes. Really no different from a lot of C compilers in this respect and with the bonus of an absolutely trivial polyfill.
- crazygringo 8y agoThe whole point appears to be avoiding nesting parentheses.
- yanis_t 8y agoNot quite sure what you mean. But how do you chain multiple functions?
- bunderbunder 8y agoWith the way syntax for function calls works, the innermost thing is executed first, and you end up reading stuff from right to left: third(z, second(y, first(x))) With the pipeline operator (and assuming a language that allows partial application), the order in which things execute matches the order in which you read it: first x |> second y |> third z The benefits start getting more noticeable when you're talking about stuff like manipulating sets of data. For example: myList |> filter (x -> x.color == 'red') |> sortBy (x -> x.count) |> first compared to these sorts of pyramids of doom: first( sortBy( x -> x.count, filter( x -> x.color == 'red', myList ) ) )