-
Notifications
You must be signed in to change notification settings - Fork 21
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
Make the fun
keyword optional
#168
Comments
+1 to fat arrows, all in the name of driving adoption for the language. |
Interesting discussion. I wouldn't support something along the lines of Haskell or Elixir-style lambdas, because instead of shortening what's already there, that would replace it with a new symbol. I'm also unsure if fat arrows would be needed - is it enough to simply make
|
sticking with let fn x y =
match x with
| 1 -> z -> x + y * z
| _ -> (z -> x - y * z)
// ^ I guess parens would be required here?
let fn': int -> int -> int = x y -> x + y I'm ambivalent about this approach, |
Good point, |
Using an available user-defined operator will break existing code, specifically The ambiguity reported by @cloudRoutine can be solved since we never match against functions, I mean we can expect a pattern between Eventually if a further enhancement allows to decompose a function (if it ever makes any sense) the Maybe even the
become
but that for sure will confuse any Haskeller. |
I don't like |
I don't hate this, but I don't love it either. Do you really think the small change will bring over people? I've never heard anyone say "I don't use F# because of the fun keyword". The grammar is also a bit more ambiguous and so difficult to parse, so it will likely always have to be in parens, saving one character on average. We don't currently use I do rather like the idea of dropping the "function" keyword though. It's obnoxiously long. |
+1 for this, not only |
+1 But more like Scala's lambda shorthand form |
+1, if it is possible to make |
When I look at my code I see a lot of lets on the left hand side that I think must be redundant. We could remove those too...I'm just joking I think. |
I don't like to remove the 'fun' from F#. I would rather discuss about an alternative syntax for very short lambda expressions. |
I like the fun keyword because it is easy to read. Sometimes having a lot of symbols make the code harder to read/maintain. When reading fat arrow or lambda from others language like Javascript, elm or haskell I am always confuse and need time to understand the code. |
IMHO, we shouldn't add more ways to do the same thing in this regard. You will not gain that much from trying to shorten syntax; only lead to more inconsitent code across large projects. The property accessor from the other issue is kinda ok, but even then even that can lead to more inconsistencies of just doing the same thing. |
As @MangelMaxime said, less keywords and more symbols make code hard to read, plus, in editors, the fun keyword with appropriate color can easily tell the structure of code |
@TIHan I agree on your point I admit that I'm in general against anything which reduces readability. It's such a strong and important feature of F# which I always use as selling point for beginners! |
I really would like Not sure |
The most annoing use for "fun" is calling methods or looking up properties in objects in pipelines (as they can't be curried away). Kotlin style lambda with implicit "it" binding would be optimal:
|
A completion snippet for |
@realvictorprm Instead of: Proposal 1: shown with a font ligature: Proposal 2: shown with a font ligature: Examples
|
For me it was unexpected to see so many opinions in favor of keeping
myList
|> List.map (fun x -> x + 1)
|> List.filter (fun x -> x < 5) myArray
.Select(x => x + 1)
.Where(x => x < 5)
let foo (f: 'a->'b, x: int) = x
let y = foo(fun x -> 5, 6) // Doesn't compile
xs |> List.map (fun x->x.Length)
xs |> List.map (x->x.Length)
xs |> List.map (.Length)
xs |> List.map _.Length @AndreuCodina Ligatures are really nice (I've also seen |
👎 If aesthetics is the sole motivator for this, I don't think it justifies the risk of introducing yet-to-be-discovered breaking changes. |
I'm only a lightweight F# user, but I find 'fun' a small, verbose niggle. When I switch between F# and C# I always use the wrong arrow for a little while, so for '.net' consistency I would like '=>'. Given how much F# has inspired C#, I think it's only polite for F# to return the favour ;-) |
really? technically yes, but alot less key strokes without |
@Happypig375 @vilinski However, conveniently, as a syntax sugar in F#, I suppose, we can write the identical mathematical entity as,
and since there is no syntax sugar in the type annotations, the type is like Then, as proposed here, dropping
should be fine, but for
This is not like making Do you suggest lambda without |
Let’s reiterate: we know that dropping ‘fun’ on single-arg functions (which technically is every function), can be done unambiguously. This part is approved in principle, and we gotta start somewhere. Syntax like The single arg option can relatively easily be introduced without Also, don’t forget that each lambda argument is a pattern, which complicates potential determinism. Again, as mentioned before, I’d vote for focusing on the part we know is possible and accepted by @dsyme (single arg) and learn from that experience before we introduce the same idea for multiple args (if at all possible to begin with). Example:
@Happypig375 Won’t work if: let x a = a * 42
let y = 12
(x y z -> x + y + z)
// function application will turn this into:
((x y) (z -> x + y + z))
// error that (x y) does not resolve to a function itself
// or error that ‘x + y’ is invalid because ‘x’ is a function and ‘y’ is 12 |
The thing, though, is that this is already illegal: x y fun z -> x + y + z
// error FS0010: Unexpected keyword 'fun' in expression It's never been possible to pass a lambda as argument to a function without parentheses. So there's no reason that making |
@Tarmil the problem is with function application. It has the highest precedence. Whereas Its similar to |
let x a = a * 42;;
//val x: a: int -> int
let y = 12;;
//val y: int = 12
fun x y z -> x + y + z;;
//val it: x: int -> y: int -> z: int -> int
(fun x y z -> x + y + z) 3 4 5;;
//val it: int = 12
(x y z -> x + y + z) 3 4 5;;
//desugars to (fun x y z -> x + y + z); you'd need parentheses for other reasons anyways. @abelbraaksma Everything between ( and -> would be an argument, just like how it is for fun. It does mean there's no way to type funless lambdas without parentheses, but that seems like a preferable choice over |
@voronoipotato in your example, the issue still isn’t resolved. There may be a way to introduce preprocessing to overcome this issue and invalidate long standing precedence rules, but it’s likely gonna be very hard. |
X will not be a function, it just desugars to fun. It will not be hard since it's just syntax sugar where the first paren gets a fun put after it. I just tested this in fsi and i couldn't see how it breaks. When you type ( followed by -> it desugars to (fun followed by ->. There's no room for any function to be run or even interpreted. Edit, there is one edge case i just thought of which is match statements but feel like you could look for the vertical bar. |
But that’s not what your code shows.
We can’t suddenly say “paren combined with I know I’m rehashing what I’ve tried to explain before. Simple: one arg approach. Very hard, maybe impossible: multi arg approach. I’d love it to be different, just trying to explain why, from a grammar & parser perspective, this is very hard, or impossible. I’d love be proven wrong, but no example or grammar rule adjustment I’ve seen so far has shown it’s possible. Try it by updating the lexing/yacc files of F#: I don’t think it can be done. Which is why this has been accepted in principle by @dsyme: the part of this proposal dealing with single arg. No scoping needed, or disambiguation wrt in-scope let bindings by the same name. |
I personally think we should just experiment with it in the dumbest way possible, and see what breaks. I'm just going to make a fake step in a build after work tonight that blindly removes all "fun" and then does a find/replace for ( and -> injecting fun in , and I'll report back on what catches fire. I know it will be more complex in practice, but if it works or can be mitigated in this trivial example then there's hope for an analogous approach. I think you may be correct, and it's very likely my ignorance saying otherwise, but sometimes the "stupid" find bizzare meandering approaches that work because they were too "stupid" to learn that what they were doing was supposed to be impossible. I really loathe the second order social consequences of making it single argument aka |
He proposed it himself, in this thread. It was what he ‘approved-in-principle’ explicitly.
That sounds like a great idea. And if some trial and error shows it isn’t as hard as I make it look, we can always go for the Full Monty. But if not, just sticking with the simple version for single arg would be a great step in the right direction. |
Well I don't doubt he approved it as is, I just would be surprised if he did it with the usage of chaining in mind. If he did consider that as a thing people do and didn't mind, then I don't care. I generally trust his judgement since the design so far has been pretty good at making bad things to do, hard to do. |
How did you get on ? |
Had personal things come up last night, thank you for reminding me. I'll give it a go tonight. Any suggestions on the repo I should try it on? |
This should probably go in the lexer, if possible, or as a postfix in the parser, fixing the AST. |
dealing with an ulcer bigger than a quarter, so it might take me a minute. I'm mostly sleeping in my free time right now, but maybe next weekend when I'm hopefully??? feeling a little better. |
oh no, hope you feel better soon |
@davidglassborow Starting to feel better, planning to try it tonight. |
@abelbraaksma @davidglassborow I played with it some, given my current understanding, I am having trouble finding any ambiguous situation. At least so long as there is a I removed all The fun I didn't remove , around 300 or so, were always preceded by an operator, comma, or whitespace. While I understand this isn't the same thing as a real attempt, this is what I'm currently capable of given my current understanding of compilers. I am honestly astonished with the regularity of lambdas as I was expecting to find a scenario that clearly would not work. (?!\sof)([\w\s]+)\(((?!match)(?!fun)(?!function)\s*[\w\s]+)->
$1(fun $2 ->
\(\(\)\s->
(() -> |
I'm not too surprised, tbh. Wherever you replace The trick is to find out if it is possible to change things like But I'd be rather happy if we can get somewhere, with what you've showed already, to have:
|
Another wrinkle to keep in mind. This
could be allowed to shed the parentheses,
It seems to me that there is no ambiguity in losing the extra clutter here, on the last argument. Swift does a similar thing to simplify the syntax of a lambda that appears as the last argument. |
I think that should be a separate suggestion, it's better we keep an existing one for one very specific feature (omitting fun keyword). |
Yes I’m just pointing out possible wider ramifications of making |
I'm teaching a class in F# next year and will need to call C# libraries. A friend of mine suggested this, which I like: |
Underscore shorthand is a separate suggestion |
Reading With underscore, it already saving a lot of this typing where |
@profK, this has been implemented and is now part of F# 8: let readOnlyFiles =
System.IO.DirectoryInfo("path").GetFiles()
|> Seq.filter _.IsReadOnly // shorthand |
In fact, I'd like to withdraw my previous statements because I'v noticed |
Submitted by Jorge Fioranelli on 3/21/2014 12:00:00 AM
271 votes on UserVoice prior to migration
Make the `fun`` optional. Otherwise it is more verbose than C#.
Original UserVoice Submission
Archived Uservoice Comments
The text was updated successfully, but these errors were encountered: