-
-
Notifications
You must be signed in to change notification settings - Fork 25
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
Operators as syntax sugar #219
Comments
I just have to say that I love this. What about precedence? I have long argued that importing math precedence into programming was a mistake and we should always require parenthesis, I guess this is implied by this proposal? |
I haven't come to a decision on that, yet. I personally wrap every math expression with parens because I can't remember the precedense rules in my head. I'll have to see how it turns out. |
I agree with your rationale on the operators. I have never liked operator overloading for that reason. However, I use currying a ton with iterators. For example: a = List.map (add 5) [1, 2, 3, 4, 5] Is your plan to have to wrap |
@dbj For your example, |
One could imagine a specific partial operator/keyword. So like: a = List.map (partial add 5) [1, 2, 3, 4, 5] |
I'm no expert, but it isn't clear to me what the type
|
Imo, `++ => concat` should also be removed. Personally I find it's rarely
used, or when it is it doesn't really help readability at all.
Personally I'd be surprised if inequality operators (>, <, >=, <=) don't
exist, and I always find it confusing to try to work with code that
avoids those operators, since the naming of the functions and the argument
order is never consistent from one API to another.
But also, I guess in a lot of code, inequality checks are rarely used, so
maybe it's fine not to have them?
…On Mon, Sep 4, 2023 at 10:32 AM Mark Bolusmjak ***@***.***> wrote:
I'm no expert, but it isn't clear to me what the type a -> b -> c means
if passing in an a doesn't give me a b -> c. In any case, is there
something that should prevent us from writing our own "partial application
helpers"?
partial1of2 : (a -> b -> c) -> a -> (b -> c)
partial1of2 f a =
\b -> f a b
—
Reply to this email directly, view it on GitHub
<#219 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAAJRSC2AZJCVMCUBA54VTXYYGCXANCNFSM6AAAAAA4KONRTE>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
btw, look to copy Swift if you do string interpolation as their system is by far the best I've seen and learned all the lessons of the languages before it. |
Oh, I guess you're right for String concat. I was only thinking of List
concat.
…On Mon, Sep 4, 2023 at 12:29 PM Anders Hovmöller ***@***.***> wrote:
++ rarely used? Hmm. Is there a nice string interpolation feature in
Elm/gren I am missing?
btw, look to copy Swift if you do string interpolation as their system is
by far the best I've seen and learned all the lessons of the languages
before it.
—
Reply to this email directly, view it on GitHub
<#219 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAAAJRUAGOLXCTSB3T3ZUWDXYYTZXANCNFSM6AAAAAA4KONRTE>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
@avh4 You're right about inequality operators. Slipped from mind when I wrote this issue. They should remain. |
Nothing is stoping us, but it leads to boilerplate code. If it is common to do, having a language convention is a good idea. |
+1 on adding string interpolation / templating for strings. |
In Elm I use List concatenation from time to time, mostly in complex views. |
Hey @robinheghan , how would this work when you are working with float and int operations in the same module? Or with having equality with different types in the same module? |
Before I answer, keep in mind that Gren is implementing parametric modules as a replacement for Elm's type classes'ish thing. That means that it won't be possible for a single function or operator to work on multiple types. As such, using operators for both Ints and Floats (or even more stuff) in the same module will be a little cumbersome. There are two ways to go about this, I suppose.
(I'm just writing this down quickly, there are probably ways to make the above more pallatable)
For equality, I'd just use the qualified functions. |
I just edited the proposal. I added a few missing operators and removed all mentions about currying. After discussions here and on the Elm slack, I'm not entirely sure about removing currying. At least, I don't think it needs to be proposed here. |
@joakin One could imagine that operators are allowed to be qualified. If so, this would also be an option:
|
Just edited the proposal. Bitwise operators were removed. It's rare to have long chains of bitwise operations, and so the benefit of operators isn't all that appearant. |
That's certainly an option, can get a bit repetitive but would work. I'm going to mention a couple of alternatives inspired from OCaml. First could be having float specific operators that you could use in the specific case you need to disambiguate between int and floats, like Another option that I think would look nice, similar to above, would be what they call locally opening a module, specifically the expression syntax. It looks like this:
Essentially it is a new type of expression that looks like this It also has a lot of other potential use cases, like for example when generating HTML, you could do:
It is a tricky problem to solve, hope these give you some ideas. Another option that could be worth considering is what Richard did with Roc, you can read a bit here. All operators desugar to a single predictable function call, and for the numbers, they are represented with a shared type |
Makes sense to make removing currying its own proposal. In my opinion worth doing, but not mixing it with the operators seems wise. |
That was a very interesting idea. Thank you for introducing it to me. The nice thing is that it can always be introduced later, after this proposal is implemented (if it is implemented).
I want Gren to only have a single mechanism for this kind of flexibility. I think it would be a worthwhile way to go if Gren was to retain the limited "type class" functionality it has now, but I do plan to rip that out eventually. |
👍
I'm not sure what you are referring to. In Roc the operators are syntax sugar for an unambiguous qualified function call, no type classes. And the numbers are defined in this clever way (something like this):
As far as I can tell, there is no type classes magic in this stuff. In the case of Roc the monomorphization will generate the right function variants for all used types, and in the case of a JS target you could just use a kernel function that is the normal JS operators which can take ints or floats and wouldn't have any problem. It solves a bit the ergonomics of the math operators, but it doesn't solve |
Why is == different? |
@joakin While The "depends on the actual type" bit is what i meant with "type classes". I assumed Roc used abilities for this, but I could be wrong. @boxed I would guess because you'd expect |
I believe since the Roc compiler is monomorphizing all functions, it ends up calling the right function at code generation. I don't think it is using type classes. If you plan to make Gren monomorphizing when you do WASM to do the most efficient assembly, this could work, and like I mentioned above it does work for the JS target. I'm trying to suggest some options since the most used operators which are listed in this proposal should be easy to use in my opinion. Imagine in your module when you want to do some math on floats and you already had math on ints, how confusing it would get for a beginner that doesn't have the context, or if you have a new |
I think we're both right. From an implementation standpoint, you're correct that there might not be anything dynamic at play during runtime. However, from the user standpoint, a function that works for all numbers is polymorphism. Parametric modules is how similar functionality will be implemented in Gren (and monomorphism is one way of implementing it, though that would come at a cost of increased asset size). While it might not be the best fit for numbers in particular, I believe it is the overall better solution. I also believe Gren is better off with just one mechanism for this (I believe Roc is exploring parametric modules in addition to abilities, which is something I'd like to avoid for Gren).
I really appriciate that! I'm just trying to explain why the Roc approach might not be the best fit for Gren, currently. =) |
Operators are easy if you already know their meaning. I would argue that most people learn the basic operators for mathematics (+, -, /, *) and tend to find their presence in programming languages unsurprising. In fact, I believe most people would find it an unecessary burden to learn how to do maths in a way that doesn't correlate to the same syntax they learned in school. In other words, I believe many would consider Gren a worse language for not having operators.
On the other hand, operators are hard if you have no idea what they mean. Most people prefer actual functions with actual names, than to read cryptic symbols with different precedense rules and inline semantics. With very few exceptions, I believe operators can make code easier to read, at the expense at making code harder to understand.
One problem with Gren's current operators, is their lack of flexibility. If someone was to create a
BigNumber
type, it would be impossible to use it with+
, even though it would make sense to use the same DSL with aBigNumber
.So, here is what I propose:
Any operator which isn't already well known or can greatly enhance the readability of Gren code, should be removed.
The operators that remain, will become syntax sugar. This means that it will no longer be possible to define operators in Gren code, even when limited to core API's.
The mathmatical operators will desugar to regular function calls:
+
=>plus
-
=>minus
/
=>divide
*
=>multiply
The implementation used, depends on the functions in scope. Since Gren plans to remove default imports, and replace type classes with parametric modules, this will give users the ability use these operators with custom types. Future
Int
andFloat
modules will implement the above functions.There are more aliases:
==
=>equals
!=
=>notEqual
++
=>append
|>
=>applyRight
<|
=>applyLeft
<
=>lessThan
<=
=>lessThanOrEqual
>
=>greaterThan
>=
=>greaterThanOrEqual
The boolean operators
&&
and||
will remain builtins, due to their short-circuiting mechanics.Operators not mentioned above will be removed.
Using operators as function references (
map (+) [1, 2, 3]
) will be a compile error. Use the named function reference instead.The text was updated successfully, but these errors were encountered: