<div dir="ltr"><div dir="ltr"><div dir="ltr"><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">On Wed, Mar 27, 2019 at 8:52 AM <<a href="mailto:zxq9@zxq9.com">zxq9@zxq9.com</a>> wrote:<br></div></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">How much once-cool-but-now-unused syntax is there in C++, Haskell, Ruby, etc?<br>
<br></blockquote><div><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">Haskell is the exception to the rule. In Haskell, you can define your own operators and give them precedence. But they are just functions in the core language. There are very few restricted keywords in Haskell (98): 28 identifiers such as 'case', 'where', 'deriving', 'class', ... and 27 symbols such as '*', '!', ... The rest are libraries defining their own operators. Almost nothing in Haskell has special handling requiring language extension.</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">Proof Assistants take this idea even further by allowing mixfix operators to be defined. Agda allows us to define if-then-else:</div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div>if_then_else_ : ∀ {a} {A : Set a} → Bool → A → A → A<br>if true then t else f = t<br>if false then t else f = f<div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">Where the underscores say where the holes are in the expression. That is, the construct is not built into the language. It is *defined* as part of the standard library[*]. This also allows far more complicated rules such as (brace for unicode!) x ·⟨ M ⟩ y, which allows us to have an operation (the dot) under a given magma[0] for elements x and y of that type.<br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><a id="gmail-3764" class="gmail-Bound" style="text-decoration:none;color:black"><br></a></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">Personal opinion: It is often better to add generic functionality to a language then special case handling. The compiler is free to optimize the generic situation if it can see some specific structure, and this has long-term support. Whereas the other way is far more restrictive (though it is often alluring). However, syntactic sugar might be necessary in certain cases, as it makes code easier to read, and often more convenient to work with. Add sugar, but add it sparingly.<br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><a id="gmail-3764" class="gmail-Bound" style="text-decoration:none;color:black"><br></a></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default">[*] Note this requires evaluation order to be lazy. You can only evaluate the two branches once you know the result of the conditional. Otherwise, you don't have the usual semantics of this construct, which is why it is often implement as a built-in into the language. If you have macro-expansion, you can build it on top of case, however.<br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><a id="gmail-3764" class="gmail-Bound" style="text-decoration:none;color:black">[0] https://en.wikipedia.org/wiki/Magma_(algebra)<br></a></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><a id="gmail-3764" class="gmail-Bound" style="text-decoration:none;color:black"><br></a></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"><br></div><div style="font-family:arial,helvetica,sans-serif" class="gmail_default"></div><br></div></div></div>