F# Language

This User Voice was for suggestions about the future evolution of the F# Language and Core Library.

I suggest we ...

You've used all your votes and won't be able to post a new idea, but you can still search and comment on existing ideas.

There are two ways to get more votes:

  • When an admin closes an idea you've voted on, you'll get your votes back from that idea.
  • You can remove your votes from an open idea you support.
  • To see ideas you have already voted on, select the "My feedback" filter and select "My open ideas".
(thinking…)

Enter your idea and we'll search to see if someone has already suggested it.

If a similar idea already exists, you can support and comment on it.

If it doesn't exist, you can post your idea so others can support it.

Enter your idea and we'll search to see if someone has already suggested it.

  1. Allow flexible types in default constructor constraint

    This would permit,

    let ctor<'a when 'a:(new: unit -> #IWebDriver)> : unit -> IWebDriver = ...
    versus

    let ctor<'a when 'a:(new: unit- > 'a) and 'a :> IWebDriver> = fun () -> new 'a() :> IWebDriver

    2 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    0 comments  ·  Flag idea as inappropriate…  ·  Admin →
  2. Allow more flexible layout for constraint syntax

    The following layout of constraints for a sample class should be possible.

    GroupedFixtures<'A, 'B
    when
    'A :> Remote.RemoteWebDriver and
    'A : (new: unit -> 'A) and
    'B :> ServerFixture
    >() as this =

    Presently it almost was but the `new()` constraint use of parenthesis caused problems. currently all the constraints layout forces them on the same line which is not as clear or convenient (note the text, that `>() as this`, is allowed on a separate line):

    GroupedFixtures<'A, 'B when 'A :> Remote.RemoteWebDriver and 'A : (new: unit -> 'A) and 'B :> ServerFixture
    >() as this =

    1 vote
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    0 comments  ·  Flag idea as inappropriate…  ·  Admin →
  3. Add a shorthand/literal syntax for creating Maps

    A shorthand/literal syntax or computation expression for building Maps would be nice—something like the following:

    let m = map ["a",97; "b",98; "c",99]

    The shorthand for dictionaries ...

    let d = dict ["a",97; "b",98; "c",99]

    ... is nice, but while Maps implement IDictionary, dictionaries do not play well with Map module functions. One must inevitably convert a dictionary to a Map or create a Map with Map.ofArray, .ofList, or .ofSeq.

    3 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    4 comments  ·  Flag idea as inappropriate…  ·  Admin →
  4. Allow function names to end with a question mark.

    I find it really elegant in some language where predicate functions can end with a question mark.

    Consider `odd? 5` vs `isOdd 5` or `areRelated a b` vs `related? a b`

    There might be some reason why it's a terrible idea grammar-wise or something in F#. I'm still very much a newbie I'm afraid. I apologize if it's featured in a FAQ I missed or even here and I search badly.

    1 vote
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    2 comments  ·  Flag idea as inappropriate…  ·  Admin →
  5. 3 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    0 comments  ·  Flag idea as inappropriate…  ·  Admin →
  6. Improve Discriminated Union Type Inference

    Sometimes the most logical name for an element of a Discriminated Union (DU), is a common concept such as a list
    -- something that you've used before elsewhere.

    The only way around the last resolved resolution is either through namespaces, or by adopting a naming convention.
    Sometimes getting nagged about name overuse can lead to clearer code, but what if our intention is exactly as
    written? In the below, if we named elements to be ListOfA and ListOfB, then the problem goes away.
    Sounds and often is simple, but it can lead to additional code noise and moves us away…

    1 vote
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    0 comments  ·  Flag idea as inappropriate…  ·  Admin →
  7. #r #load via fsi method

    fsi.Load("script.fsx")
    fsi.Reference("bin/debug/someDllReference.dll")

    It would be very useful to be able to fsi.Load / fsi.Reference through type providers, for use by those who are designing them.

    1 vote
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    2 comments  ·  Flag idea as inappropriate…  ·  Admin →
  8. Map keys <--> set compatibility

    A map's key collection is a set and should be treatable as such. Currently (AFAIK) you must get the keys from the map like so:

    let keys = Map.toSeq >> Seq.map fst

    then create a set from the (k,v) seq:

    let set1 = keys map1 |> Set.ofSeq

    and then perform your set operation:

    let common = Set.intersect set1 set2

    This involves creating a temporary collection and a new set.

    There are several ways to improve things:

    (1) Provide a Map.toKeySet & Set.ofMapKeys functions that will directly and efficiently create a new set from the Map's keys. This is straightforward and…

    2 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    0 comments  ·  Flag idea as inappropriate…  ·  Admin →
  9. Add Polymorphic Variants (ad-hoc Discriminated Unions)

    Creating strongly typed data constructs with some level of heterogeneity is often accomplished with DUs so lets take the trivial case of wanting
    to have lists of floats & ints, ints & strings, and ints & floats & strings
    We'd need the types -

    type IntString =
    | Int of int
    | String' of string

    type FloatInt =
    | Float of int
    | Int of int

    type IntFloatString =
    | Float of int
    | Int of int
    | String' of string

    But in practice using these would require qualified access to make sure you're getting the right case from the…

    36 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    1 comment  ·  Flag idea as inappropriate…  ·  Admin →
  10. extend ComputationExpression builders with Map : m<'a> * ('a -> 'b) -> m<'b>

    In many scenarios computation expressions could be executed way more efficiently when having just a little more information.

    The typical use-case for that would be something like

    async {
    let! a = something
    return 2*a
    }

    which currently gets translated to:
    async.Bind(something, fun a -> async.Return(2*a))

    By monad laws (borrowed from haskell here) this must be equal to:
    async.Map(something, fun a -> 2*a)

    In many scenarios the latter can be implemented with a lot less overhead, so in my opinion it would be profitable to allow users to provide this "shortcut".

    8 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    0 comments  ·  Flag idea as inappropriate…  ·  Admin →
  11. Optionally relax signatures of -X, sin X, cos X to allow use w.r.t. subtyping

    See https://github.com/Microsoft/visualfsharp/issues/799

    type Base(x : int) =
    member self.X = x
    static member (~-) (a : Base) = Base(-a.X)
    static member (+) (a : Base, b : Base) = Base(a.X + b.X)
    static member Cos(a : Base) = Base(2*a.X)

    type Derived(x : int) =
    inherit Base(x)

    let a = Base(1)
    let minusa = -a // OK
    let cosa = cos a // OK
    let twoa = a + a // OK
    let b = Derived(1)
    let minusb = -b // Compile error
    let cosb = cos b // Compile error
    let twob = b + b // OK

    3 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    1 comment  ·  Flag idea as inappropriate…  ·  Admin →
  12. Allow implementation of abstract slots with generic return type instantiated at type 'unit'

    The behavior described here,

    http://stackoverflow.com/questions/26296401/why-is-unit-treated-differently-by-the-f-type-system-when-used-as-a-generic-i

    is quite surprising to someone coming from other typed FP languages. The fact that a generic type parameter can't be unit makes the whole generics abstraction feel a bit leaky and hacky, which isn't great publicity, as F# actually has a lot of great ideas.

    In practice this comes up when implementing type indexed values of various sorts, as an interface is an ideal and natural way to do that, and of course one often wants to have a sometype<unit> value. The compiler error is rather surprising as well, as it implies the object expression…

    7 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    0 comments  ·  Flag idea as inappropriate…  ·  Admin →
  13. In a pattern match use the record field name as a default binding if none is provided

    In OCaml we can do,

    match somrecord with
    | {foo; bar; baz} -> foo + bar + baz

    If we don't provide a binding, then the field name is used as the default. In F# we still have to write,

    match somerecord with
    | {foo=foo;bar=bar;baz=baz} -> foo + bar + baz

    This is quite a simple syntactic enhancement, however it's very nice to have. It also pushes us to use the (presumably) well chosen record field names for our variables instead of picking a single letter variable name.

    Also, in OCaml we get a warning if we don't bind all…

    13 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    0 comments  ·  Flag idea as inappropriate…  ·  Admin →
  14. Expand support for byref to match C# 7

    C# is adding support for byref locals and returns (see https://github.com/dotnet/roslyn/issues/118, slated for milestone 1.3). This will result in many libraries that expose these features (which the CLR already supports), but methods with such return types aren't currently usable from F#. F# already supports byref locals, but doesn't support implementing byref-returning methods nor does it support calling byref-returning methods.

    At a minimum, F# should support calling byref-returning-methods (e.g. SomeRefReturningMethod(x,y,z) <- w), since C# users will be creating methods like these and being unable to call them will limit F#'s reach.

    It would be nice if on top of that…

    14 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    2 comments  ·  Flag idea as inappropriate…  ·  Admin →
  15. Richer literals: TimeSpan/DateTime/Char array/UTF8

    Combining several suggestions for richer literals

    - New literals for TimeSpan and DateTime. e.g.

    "01:02:03"T --> new TimeSpan(1,2,3)
    "2015-01-02 10:30:00"D -> new DateTime(2015,01,02,10,30,00)

    - Char[] e.g

    "abcd"C

    - UTF8 encoded strings "abc££def"U

    and indeed perhaps the whole mechanism should be extensible like QZRING literals

    4 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    1 comment  ·  Flag idea as inappropriate…  ·  Admin →
  16. Introduce the ?. operator into F#

    Since we allow the . operator to reference fields and properties of objects in F#, we're faced with the same problem of null checking that plagued C# until C# 5.

    The C# 6 'elvis' operator propagates nulls in a succinct way, and I think that working with objects in F# will be similarly simplified if we introduce it here as well!

    16 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    6 comments  ·  Flag idea as inappropriate…  ·  Admin →
  17. Allow all declarations to be mutually referential and the compiler takes files in any order

    With F# becoming more and more multi-editor and cross-platform, it is becoming increasingly difficult to teach all build/edit tools about F#'s file order. The F# community are currently struggling to "update" each new build/edit tool to understand that F# actually needs a file order.

    Part of the problem is that there is no standard textual way to specify this file order except as command line arguments, and these are not stored in an editable form. There is no standard way to specify the F# file order. We need an (optional) solution to this problem that is closer to home and…

    39 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    29 comments  ·  Flag idea as inappropriate…  ·  Admin →
  18. Catch improper use of monadic return in async

    The following code should issue a type checking error since return () should yield an Async<unit> and return 42 should yield an Async<int>.

    let f c =
    async {
    return ()
    printfn "You passed %A and I am returning 42" c
    return 42
    }

    Additionally the following code should issue a warning since the return statement does not actually affect the flow of execution as the name suggests (The printf statement is actually executed).

    let g c =
    async {
    return ()
    printfn "You passed %A and I am returning 42" c
    return ()
    }

    11 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    2 comments  ·  Flag idea as inappropriate…  ·  Admin →
  19. implicit upcast of return values

    It gets to be very frustrating when working with many C# libraries from F# because F# lacks implicit upcasting of return values. In some cases, this is just annoying. But it is particularly intractable when dealing with libraries expecting Expressions, because upcasting changes how the expression is evaluated by the library. See this question, where in the comments, the author comes to the conclusion that he can't make it work with F#.

    http://stackoverflow.com/questions/10647198/how-to-convert-expra-b-to-expressionfunca-obj

    There does exist a work-around, but it is quite horrible.

    http://www.fssnip.net/c7

    Aside from this show-stopping issue, there are many other scenarios where libraries expect implicit upcasts and…

    6 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    0 comments  ·  Flag idea as inappropriate…  ·  Admin →
  20. Produce System.Linq.Expressions more efficiently

    Most of .NET query providers are written in C# and use System.Linq.Expressions. While the conversion Expr->Expression is available it introduces significant penalty: http://stackoverflow.com/questions/32592811/why-is-f-expression-tree-generation-is-much-slower-than-c-can-it-be-made-fast

    30 votes
    Vote
    Sign in
    (thinking…)
    Sign in with: Facebook Google
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    3 comments  ·  Flag idea as inappropriate…  ·  Admin →

F# Language

Feedback and Knowledge Base