What is the collection initializer syntax in F#? In C# you can write something like:
new Dictionary() {
{\"One\", 1},
{\"two\", 2}}
As Jared says, there is no built-in support for this for arbitrary collections. However, the C# code is just syntactic sugar for Add
method calls, so you could translate it to:
let coll = MyCollectionType()
["One", 1; "Two", 2] |> Seq.iter coll.Add
If you want to get fancy, you could create an inline
definition to streamline this even further:
let inline initCollection s =
let coll = new ^t()
Seq.iter (fun (k,v) -> (^t : (member Add : 'a * 'b -> unit) coll, k, v)) s
coll
let d:System.Collections.Generic.Dictionary<_,_> = initCollection ["One",1; "Two",2]
You can use the same :
open System.Collections.Generic
Dictionary<int, string>(dict [ (1, "a"); (2, "b"); (3, "c") ])
Cheers.
I don't believe F# has an explicit collection initializer syntax. However it's usually very easy to initialize F# collections. For example
let map = [ ("One", 1); ("Two", 2) ] |> Map.ofSeq
Getting to BCL collections is usually a bit more difficult because they don't always have the handy conversion functions. Dictionary<TKey, TValue>
works though because you can use the LINQ method
let map =
let list = [ ("One", 1); ("Two", 2) ]
System.Linq.Enumerable.ToDictionary(list, fst, snd)
The lack of a collection initializer is annoying for some XAML-centric APIs like Workflow 4.0 which rely on collection initializers instead of ctors, e.g.
new Sequence { Activities = { WriteLine { Text = "In the sequence!" } } };
In such cases, imperative .Add() is awkward because the value is conceptually declarative even though it's technically mutable/imperative. However, there's no common base class for the set of all activities which declare an Activities child: the "Activities" member is a pattern and not an interface, so you can't just write a normal helper function which adds children to any activity. Fortunately, F# member constraints come to the rescue.
In order to write this:
Sequence() |> add [Sequence(DisplayName="InnerSeq"); WriteLine(Text = InArgument<_>("In the sequence!"))]
You first need to define an inline helper function called "add":
let inline add (children: Activity seq) =
let inline doAdd (activity: ^Activity) : ^Activity when ^Activity : (member get_Activities : unit -> Activity Collection) =
let collection = (^Activity : (member get_Activities : unit -> Activity Collection) (activity))
for child in children do
collection.Add(child)
activity
doAdd
This still isn't quite as nice as the C# syntax but at least it's still declarative. IMHO this is not so much as a fault with F# as with collection-initializer-centric APIs, but at least F# allows a workaround.
Given that the C# collection initializer syntax is syntactic sugar for calling .Add
and that implies a mutable collection - I'm not sure you'll see any such syntax in F#. It's initialize all in one go as per JaredPar's answer, or do it manually.
To elaborate a bit on collection initialization in F#, here are a few examples:
read-only dictionary
dict [ (1, "a"); (2, "b"); (3, "c") ]
seq (IEnumerable<T>)
seq { 0 .. 99 }
list
[1; 2; 3; 4; 5]
set
set [1; 2; 3; 4; 5]
array
[| 1; 2; 3; 4; 5 |]