Comment by amelius
3 days ago
I want to put the called function after the arguments:
(((x)f)g)h
So I can see exactly the order in which things happen, from left to right. As opposed to:
f(g(h(x)))
where I have to read backwards.
3 days ago
I want to put the called function after the arguments:
(((x)f)g)h
So I can see exactly the order in which things happen, from left to right. As opposed to:
f(g(h(x)))
where I have to read backwards.
One of the things I love about programming in dialects of ML like ocaml and f# is the forward pipe operator:
It's nice because it just puts whatever's on the left of the operator in as the last argument. So it also works for functions with an arity of more than one.
So if it were something like
you can write it as
It works really nicely for data munging code:
but unlike doing it with method calls in object oriented code, inserting a new function into the chain doesn't involve modifying a class or or mucking around with more complex language features like extension methods and traits.
There's also function composition
Or for LtR, with Control.Category
Could combine with the forward pipe for
Lisp macros let you do similar things, and you don't have to change the language itself.
In ML family languages you also don't have to change the language for this, as function application is naturally "argument-by-argument" (the term is "curried"): the syntax is normally f x y z but (f x y) z and (((f)) (x)) y z are just as valid, and indeed f x y will be a function taking one argument. Thus |> can just take a function of one argument and be done.
Maybe I've just been doing too much Racket lately and that's affecting how I view things, but it's real hard for me to not think of lisp macros as a mechanism for changing the language itself. Especially if it's something like a reader macro.
1 reply →
You could say the same about more or less any language feature - the thing is though that having a standard feature people can agree on is better than several people’s divergent opinions on which macros are sufficiently aesthetically pleasing.
Mathematica has a crazy amount of syntax abbreviations (https://reference.wolfram.com/language/guide/Syntax.html). Of course your whish is fulfilled there: x // f called the postfix operator.
Do you mean (((x)h)g)f ?
since the order in which things happen is "h first, then g, then f"
So would you like to write shell commands connected with pipes like that too?
So is this better too
than ?
Just because shell actually starts executables right to left when using pipes. Reason to this behaviour is because it can fail early if there is problem constructing pipe first and not spend lot of time something finding later that some pipe components can't start and receive data properly.
ps. I'm fine with current notation and would not like change it.
I think he actually wants pipes. Instead of having to write:
it would be nice to write
javascript has proposals for pipe operators because as soon as the simple .map /.filter/.reduce APIs don't suffice (ie. as soon as Promise.all is needed) the f3(f2(f1(data))) mess starts.
I have also used ramda for this
R.pipe(f1,f2,f3)()
F# for the win!
Did you even have an RPN-based calculator at school?
As to more serious programming languages, Erlang, F#, Haskell have forms of a "pipe" operator, roughly
For it to work properly, functions should be either functions of one argument, or support currying.
But the original algebra functions, as introduced by Leibniz in 17th century, were, of course, pure functions, more like properties than procedures. So cos(x), aka cos x, is just a formalized shorthand for "cosine of x", so it preserved the order of words typical for Germanic and Romance languages. Maybe if functions were introduced by the Japanese, we would have the reverse order, kind of x の cos.
This has been proposed but never adopted : https://github.com/tc39/proposal-pipeline-operator
I think you mean Elixir, unless Erlang added a pipe operator in the last 10 years...good grief I've been out of that world too long.
Yes, Elixir, of course; thank you!
Assuming you mean h)g)f, you can do it in D. D allows you to write this:
f(g(h(x))) as x.h().g().f() or even x.h.g.f (parenthesis are optional).
That actually makes so much sense...
When you're calling a function, you're putting some things into the function... You have to get the things first before you can put them in...
Why didn't it evolve like that in the first place? Is it a byproduct of mathematical notation? If so, I wonder why mathematical notation evolved that way in the first place...
Forth (or Postscript by the way) works exactly like that, but writing the function first also makes sense in functional programming, specifically when you care about currying functions: writing "f(g(h(x)))" (or "f g h x" or whetever) makes more sense, since you are not supposed to put all expected arguments at once.
Do you have to write a function first before it is referenced in PostScript? (I did a lot of PostScript programming in NeWS once - but it was ~35 years ago...)
> Why didn't it evolve like that in the first place?
It did, just in Arabic.
Stack based languages and the APL tradition all follow this pattern, which I agree can be more terse and nice too. I've also been experimenting with right-associative calls which does the same thing but in reverse. For a data pipeline you're more likely to transform from A->B, so I think the post-fix syntax makes sense.
But you can also define a "thread" operator easily for doing subsequent function calls. ala `threaded x { f; g; h }`
I want to put the function below the arguments, so that the call tree actually looks like a tree
This is h(f(u,v), g(x,y)).
I've thought about this before. It gets harder when dealing with >2 inputs and names longer than 1 letter, so I organized it with lines to make it look more tree-like.
With >2 inputs and longer names.
The associative property.
The quadratic formula.
Obviously, it takes way more space and time to draw. Tell me if you like it!
Yes! Just like all notations other than f(x, y), it's beautiful and completely impractical.
In a lazy language like Haskell, the order in which things are actually evaluated is f -> g -> h -> x, because arguments to a function are only evaluated when the are needed, rather than before they are called. But even so, I still prefer writing it as x |> h |> g |> f.
And that's why "purely procedural" languages don't make much sense to me
It's more natural to write
If `f` is an expression, that would require it to be evaluated last as well.
This is why some languages have the | pipe syntax for chaining operations.
you can start with
if you need to partly curry to free first argument
if you want whole pipeline
which gives fun ability to extract function without input param
... which in turn is just having fun with point-free JS
[flagged]
The function reference is actually evaluated first so your preferred order is actually backwards! Consider this:
The `foo.bar` field has to be retrieved before the function can be called. It does not evaluate `x` first. That is observable with JS proxies, or you can test with code like this:
Executing the "." operator isn't the same as executing the function.
JS and many other languages have getters so that's not always true.
But my point is that the reference to the function you are calling is actually its own term that needs to be considered in the order of evaluation.
You can also use the IIFE (immediately invoked function expression) pattern that is/was common in JS as an example:
You can use any valid expression in place of a function name, including anything that causes observable side effects.
1 reply →