F#: Is the "fun" keyword necessary?
Asked Answered
N

4

21

I was typing the "fun" keyword and then I remembered you don't have to in C#

Wouldn't this:

List.map (x -> x + 1) [1..10]

Be just as expressive as this?:

List.map (fun x -> x + 1) [1..10]

This makes me curious as to why the "fun" keyword is necessary at all. Can someone clarify why the "fun" keyword is syntactically required?

Narrow answered 18/12, 2009 at 0:10 Comment(11)
I don't know anything about F#, but I find the fact that it has a keyword named "fun".. funnyAirbrush
because coding in F# is fun! Its a friendly reminder while coding :)Aldis
If they took it out, there would be no fun in f#! Seriously though, that's curious as lambdas in C# don't need the keyword. It may be there just to simplify the parse. As languages evolve, these sorts of things tend to get reduced out/made optional.Ginder
Good point re evolution @Jim. It may be an aid to reduce the learning curve of F# and once it is/may be more widely used keywords which are implied may be removed.Aldis
it's necessary if you want it to compile :)Leshalesher
Isn't the fun keyword also a leftover from the ML family of languages? Haskell seems to get by okay with just using a backslash.Penitent
@yatima2975: I'm not really sure a backslash is so much less. It's a couple of characters shorter — otherwise they're identical. Both are tokens indicating a lambda.Schenk
A nice Haskellian backslash would be nice, instead of fun. Well at least it reminds me more of the lambda symbolNosepiece
@yatima2975: Yes, SML has 'fun' too.Spiccato
Strangely, SML uses fun in place of let rec. The equivalent to OCaml and F#'s fun is fn.Schenk
Beside, there is an issue about this on GitHubShellashellac
S
24

The language is ambiguous without it.

let x y = y z -> y z

Does x call y on the function z -> y z or does it ignore its argument and return the function y z -> y z?

Schenk answered 18/12, 2009 at 0:20 Comment(4)
hmm good point, but surely you could add parenthesis to solve the ambiguity: "y (z -> y z)"? hmm... would that just end up making things more verbose?Narrow
But then you've just transformed fun into (). C# can get away with not having a special syntax for lambdas because it has a more elaborate syntax to begin with. In a language like F#, I don't see how you can get around using some kind of delimiter to say "OK, lambda coming up!"Schenk
I don't think this has to be ambiguous, most languages have tons of ambiguity, and there are precedence rules that are used to 'break' the ambiguity. This could possibly be another such case.Shavers
@Brian: I'm trying to think of how such a rule would be expressed without making other parts of the language more confusing. It seems like the only simple choices are "every identifier before a -> is an argument" (the "turn fun into ()" option) or "lambdas only take one argument" (which I guess would bring us closer to lambda calculus). There's probably another option I haven't thought of, but I do think fun is a pretty simple solution here.Schenk
S
17

Lots of decent speculative answers already... I'll add to the mix:

F# has a core language that's compatible with OCaml, and OCaml uses 'fun'.

Shavers answered 18/12, 2009 at 0:27 Comment(0)
S
0

I just wanted to share that now it is possible (since f#8) to avoid the fun and lambdas altogether at least in a very specific situation: when your lambda is nothing more than an atomic expression (that means, when the expression in you lambda does not has any whitespace outside of a parentheses, like when you pass multiple curried arguments to a function.)

For example:

let exp1 = [{| X = 0; Y = 1; |}] |> List.distinctBy (fun x -> x.X)
let exp2 = ["A"; "B"; "C"] |> List.map (fun x -> x.ToLower())
let exp3 = List.map (fun x -> x.CompareTo(5)) [1..10]

Can now be written as:

let exp1 = [{| X = 0; Y = 1; |}] |> List.distinctBy _.X
let exp2 = ["A"; "B"; "C"] |> List.map _.ToLower()
let exp3 = [1..10] |> List.map _.CompareTo(5)

Notice that, in the case of exp3, I had to pass the data argument to the front and pipe the function, so the type inference knows that _ is an int in that context.

Spangle answered 13/6 at 4:31 Comment(0)
A
-1

I know as part of currying, (see this post) you can replace:

let countOneToTen = fun y List.map(fun x -> x + 1) y
countOneToTen = [1..10]

with

let countOneToTen y = List.map(fun x -> x + 1) y
countOneToTen = [1..10]

without the fun keyword.

Aldis answered 18/12, 2009 at 0:18 Comment(4)
That's not what the OP is talking about. They are instead asking why fun x -> x + 1 can't just be x -> x + 1.Dissimulate
The question is asking whether "the 'fun' keyword is necessary at all," I was giving another example of where it can be used and omitted depending on developer preference.Aldis
I know (and I'm not the one who downvoted you, to be clear). Although I honestly don't know why anyone would prefer the version that doesn't take advantage of partial application. :)Dissimulate
I see where you are coming from @bcat. This is a scenario where I would use the partial application of it as well, however I was talking more general. I find (assuming the functions are named correctly), currying functions (apart from reducing no. param values) provides a clearer flow of code. (*Note: I am still learning F# too! :) )Aldis

© 2022 - 2024 — McMap. All rights reserved.