-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Concern on Hack pipes on algebraic structure in JavaScript #223
Comments
To be fair, I already received a feedback
My answer is:
I disagree
Only half correct. Extracting the context, state from outside is also "side-effect". Having said that the definition of the term is not an essence here. What does matter is we can extract internal variables with the operation of hack-pipe, and that never happens in math function that is referential transparent in the definition. They say F# can do the same, and in fact not. We decalair a new function There are no context variables to leak outside. The variable of Please note: the above code essentially corresponds to the comment:
On the other hand, hack pipe leaks the context variables |
Hack pipeline operator no longer satisfies Associativity law.In this comment, I will explain how Hack pipeline operator has broken Associativity law in algebra.
In my first post, I commented:
and in the page, there is a section mentioning Associativity So, you may be wondering why they care Associativity in programming. In fact Associativity is one of the most important concept in programming and Associativity is the key to avoid the software complexity that is the fundamental reason of BUGs . In other words, as long as we are very carful to keep things with associative property, we safely can avoid complexity and obtain a bug-free code.
and this is a very important information to remember for us because as long as we are within this rule, the code will not be broken, for instance we can extract or replace The point is we had never had this kind of perspective of associativity in OOP or other codes: Further more, there are more robust algebraic structure: Monoid
What does this mean?
Strings and Of course, the plus operator As I mentioned in my first post here, If we are very careful to treat programming entities kept equal all the time, we safely can avoid the problem of combinatorial explosion.
Therefore, when we operate Strings with The Wikipedia page smartly mentions functions. Yes, function composition is a monoid.
So,
The all combinations of functions are equal and robust like Strings operation. Now, do you want to write this in with hack Pipeline-operator So, Function composition I like to prove monad property with function-composition because I think it's elegant, but since Haskell Monad laws seems to be well known, I have a code to prove in both ways. Hack pipe
Remember math or functional of minimal-style, or F#-style pipeline operator always satisfies the Associative law, which does not apply to hack-style. |
Pardon my naivete, but isn't it permitted with hack ? a |> f(^) |> g(^) |> h(^) ===
a |> f(^) |> (g . h)(^) ===
a |> (f . (g . h))(^) ===
a |> (f . g)(^) |> h(^) ===
a |> ((f . g) . h)(^) ===
a |> (f . g . h)(^) |
@fuunnx Thanks for your inquiry, and sure it is permitted, and I am very afraid of the possibility they will also mess function composition operator There are infinite number of binary operators in theory, like monad operator might be assigned to In terms of breaking associativity, as I wrote in the final section, it's only for unary function calls, and n-ary function calls or others does not satisfy Associative law because the operator is no longer compatible with function composition. Remember math or functional of minimal-style, or F#-style pipeline operator always satisfies the Associative law, which does not apply to hack-style and this is a huge problem. |
You gave this example: You can rewrite it as On the other hand, F# |
For
I'm sorry you are wrong. In JavaScript, In ES2019, Array.flat() and Array.flatMap() has been newly introduced.
Why do we need this?
With the robust aspect,
Array.flatMap() is a Monad method that has associative property in definition. |
Having said that,
This is interesting and I have no idea what's going on. What does Since a programmer recognize the pipeline operator as Is
?? Could you explain please? @nicolo-ribaudo |
Several people already showed you that F# pipe transplanted into JS is not associative. If you want to prove associativity (i.e. that rearranging parentheses doesn't change the outcome), you cannot replace operators to fit your claim. Just like I cannot prove that division is associative with this: (a / b) / c === a / (b * c)
It's not a function at run-time, it's not even legal syntax on its own. But if you really stretch the meaning, it is a "function" of the topic variable in the grammar — it can only appear on the RHS of pipe operator, which applies the "function" to the LHS. If we denote the RHS expression as a function of the topic, the Hack pipe operator is associative: ( x |> (f(^) |> g(^)) ) == ( x |> g(f(^)) ) == g(f(x))
( (x |> f(^)) |> g(^) ) == ( f(x) |> g(^) ) == g(f(x)) The proposed Hack pipe in JS operates on parse nodes, not run-time values. Perhaps that's what confuses you. |
Please note: I'm not talking about F# implementation, but talking about Algebra. That is the on-topic here.
You don't understand.
at the same time,
I'm sorry it seems you have not studied the Haskell page I linked: For your convenience, I would rewrite to
No, I just did the math, Ok? |
So a member here claimed the hack
Now, you (@lightmare) claim In mathematics, there is no such situation So here we have confirmed the fact hack |
Thanks for the explanation. I find it super confusing that you're using two different meanings of associativity in your posts, and sometimes couldn't tell which one you're talking about. You were not proving that
The part of the expression you used is only valid on the right-hand side of the pipe operator. If you want some comparison to math, it's as if you wrote a lone superscript |
It's the identical meaning in algebra and just layer is in Monoid (S = S * S) or Monad (M = M * F) . I don't know what you mean by super script, here I only describes the algebra laws, and you admit Any objections against hack |> is no longer a math operator and breaks the law of algebra? |
Why does it matter if it's a math operator or not, exactly? The goal of the proposal isn't "provide a math operator that follows some set of laws", it's "to help linearize nested function calls". If that's achieved with something that follows X set of laws, great! If not, that's fine! |
Is there such a consensus? Do we share the fact hack pipe is no longer satisfies a very basic law of algebra that is Associativity? Have you compared PRO and CON of F# doesn't violate the law of math, and on the hand Hack violates? |
@stken2050 the term "consensus" with tc39 proposals typically only refers to consensus among TC39 delegates; the goals of a proposal are usually dictated by its champions. I think if you want to be persuasive, you'll have to demonstrate concrete impacts - in the same way as "Promises aren't monadic!" didn't end up persuading the committee, "hack pipes aren't algebraic" likely won't either. |
@ljharb
And yes, I would not consume my time if it's for Promises, but this is about a very basic binary-operator that breaks the very basic law of Algebra. |
@ljharb In fact, I thought I mentioned in this aspect in my initial post here:
A replacement of a syntax "to help linearize nested function calls" is fundamentally achieved by the implementation of the binary operator that is essentially a algebraic structure, and that is called expressions. https://en.wikipedia.org/wiki/Expression_(computer_science)
Binary operator is in math realm in definition, so this should strictly follow the math rules. In contract, there are statements https://en.wikipedia.org/wiki/Statement_(computer_science)
Why expressions are safer and make better building blocks
Basically, there is not much space to have fun for us to tweak specifications for expressions-binary operator because essentially the specifications are fixed in mathematics. On the other hand, statement is for specifications that probably you are more interested in. "to help linearize nested function calls" is not achieved by statements of human designed. The problem of hack-style is this is a work of crossing the border between statement and expression, which we should avoid. @js-choi and other often mentions "interoperability" and the concept is used to justify the crossing the border. In Haskell, expressions or operator is not allowed to violate the math rules for interoperability. Do notation is a statement of Haskell which is simply a syntax sugar on the monad operator For the interoperability of According to Brief history of the JavaScript pipe operator Actually, it's not an adequate manner to fit binary-operator that is defined in math to a statement by human design. In fact, I have never seen the math operator in JavaScript is spoiled in math sense in order to fit to some statement in JavaScript. |
For how much impact will be brought due to the math inconsistency. Honestly, I don't know. Object-Oriented Programming — The Trillion Dollar Disaster Designers of OOP language have misunderstood they were smarter than math structure and invented various "best" mechanism for them.
Programming become much more mathematics in this decade. https://doc.rust-lang.org/reference/statements-and-expressions.html Statements and expressions of RustRust is primarily an expression language. This means that most forms of value-producing or effect-causing evaluation are directed by the uniform syntax category of expressions. Each kind of expression can typically nest within each other kind of expression, and rules for evaluation of expressions involve specifying both the value produced by the expression and the order in which its sub-expressions are themselves evaluated. In contrast, statements in Rust serve mostly to contain and explicitly sequence expression evaluation. Why expressions over statement? Statements, in contract, are not math but mechanisms designed by human ideas without any evidence but with their personal experience, such as
this is the form of failed software development. Now Rust is a language of expressions, functional (math) language. Popularity of TypeScriptThe popularity of TypeScipt is also an evidence of JS community become to respect Math more than ever. Why? Because fundamentally type is sets of Map (mathematics) == function https://ncatlab.org/nlab/show/type+theory#type_theory_versus_set_theory
Types as Sets · An Introduction to Elm
In JavaScript we prefer much more strictness of the definition of functions. Our way to treat Function in JShttps://en.wikipedia.org/wiki/Function_(mathematics)
binary relation between two sets This is the brief definition of function, and since we need to define Sets property we have "type" in programming. One more factor is binary relation, therefore we have binary operator
Since this is also the very basic factor as Sets==Type, we need to implement this binary operator to JS with respectfully, carefully without messing up the Math structure.
What do you mean by the word of "remotely"? To me taking a risk to disrespect math itself is a huge risk. I feel very insecure. |
What i mean is, it does not make a difference. I still fail to understand why - beyond philosophical/ideological concerns - it would have any concrete negative impact if things don't "follow math". |
This is not established as an answer for my question at all. "philosophical/ideological concerns" does not reflect our reality as long as the thing have not happened yet. My "philosophical/ideological concerns" corresponds to the reality that actually have happened in the history of our software development, which I should call "evidence".
Programming is a math. Please refer the word of "Computation". Haskellers just do algebra in their code but they also take advantage of a syntax of statement Imperative Programming for human being, and the point is they have never broken the the mathematical structure of the binary operators. Hack pipe is the first binary operator that breaks algebraic structure (function application) in JavaScript. |
I'm closing this issue. While F#-style pipes can be understood in terms of functional algebra, JS does not in general require that of any of its features. And fwiw, expression algebras also exist, and Hack-style pipes should be expressible in terms of them. Regardless, tho, the issue raised by this thread isn't something we worry about in JS. |
Since a moderator marked my post as off-topic even though I firmly believe my post exactly corresponds to the issue where I thought myself invited to because I was told so, here I start my own new issue and this first post is exactly the on-topic.
First of all, I appreciate @js-choi 's hard work (must be, I guess) for Brief history of the JavaScript pipe operator
that I think the information listed is extremely valuable for everyone who concerts the matter.
Here I would like to express my concern on Hack pipes on algebraic structure in JavaScript.
Reading through his work describing the history, I feel very sorry for this proposal, especially @rbuckton's contribution.
Fundamentally, essentially, this proposal is to introduce a new binary operator to JS, which is the same league of exponentiation operator
**
introduced In ES2016Syntax
Math.pow(2, 3)
==2 ** 3
Math.pow(Math.pow(2, 3), 5)
==2 ** 3 ** 5
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation
Replacements an expression of OOP style to a binary operator in an algebraic sense make the code concise and readable, easier to grasp the math structure which leads us to avoid mistakes then the code becomes robust. This is a very powerful approach, and perhaps some people observe this manner as FP code. Haskell codes are full of binary operators, and Haskellers basically do just Math/algebra in their code.
A replacement of a syntax
f(x)
==x |> f
g(f(x))
==x |> f |> g
is the same league of
**
binary operator.Replacement and replaceable or equivalent itself is a very powerful concept. Why? Because equivalency reduces complexity.
The history of software development is a war against complexity.
If we are very careful to treat programming entities kept equal all the time, we safely can avoid the problem of combinatorial explosion.
https://en.wikipedia.org/wiki/Combinatorial_explosion
So, to keep entities of programming equal or to be replaceable equally all the time is an extremely important concept, and although I don't like to use this term, many call this advantage referential transparency.
https://en.wikipedia.org/wiki/Referential_transparency
Obtaining a concise binary operator contributes to reduce the complexity of our codes.
Math.pow(Math.pow(2, 3), 5)
==2 ** 3 ** 5
g(f(x))
==x |> f |> g
Of course, the above code is referentially transparent. They are Just math equations, and since things are always equal and replaceable, we are guaranteed to be safe from the complexity of combinatorial explosion.
On the other hand in hack "operator", I mean mathematically operator is "pure" in concept but this one is not "pure", we are not safe any longer.
g(f(x))
!=x |> f |> g
g(f(x))
!=x |> f(^) |> g(^)
The hack "operator" spoils equivalency and referential transparency or introduces a side effect.
The side effect is to introduce a new context variable
^
.This fact has been apprehended with certainty here recently:
Question about ^ when a "child pipeline" is present. #208
#208 (comment) @mAAdhaTTah
The reason programmers avoid side effects is this is the factor of complicity and fundamentally this is mathematically inconsistent.
https://en.wikipedia.org/wiki/Referential_transparency
Losing referential transparency, a real-world programmer who has used hack-style-operator for a certain period of time actually has been suffered.
#202 (comment) @kawazoe
new
this
?microsoft/TypeScript#43617 (comment) @weswigham
this
is a bad legacy of OOP and very hard to control. To be fair, as @js-choi suggested,this
is dynamic and#
or^
is lexical, however, both of them have a fixed name and it appears in any layers of deepness.It's not my intention to make the topic broader and there is an active-sub topic Tacit programming / point-free style and pipes #206
however, the fundamental reason F# style(true functional pipeline operator) automatically fits on point-free style is simply
g(f(x)) == x |> f |> g
They hold concise mathematical equality and did not mess up the algebraic structure. then referential transparency.
On the other hand, with hack-style, obviously, we encounter problems to reach that.
Why? because losing equality and the math is messed up.
g(f(x)) != x |> f |> g
g(f(x)) != x |> f(^) |> g(^)
JavaScript is originally developed by Brendan Eich, a functional programmer who had been Scheme enthusiast. That's why JavaScript has a core feature of functional language such as functions are first-class objects.
Now, we have a pipeline "operator" that should have been considered as a very basic binary operator of function application that is a very basic algebra operation in the mathematical sense but actually polluted by a side-effect.
Concern on Hack pipes on algebraic structure in JavaScript
With Hack pipes, we've lost JavaScript as a functional language. Perhaps that's why many are upset. It's not a matter of "interoperability", and "silent majorities" will care about this matter a lot.
The text was updated successfully, but these errors were encountered: