Синтаксис инициализатора коллекции F # - PullRequest
32 голосов
/ 17 марта 2011

Что такое синтаксис инициализатора коллекции в F #? В C # вы можете написать что-то вроде:

new Dictionary<string, int>() {
    {"One", 1},
    {"two", 2}}

Как мне сделать то же самое в F #? Я полагаю, я мог бы свернуть свой собственный синтаксис, но, похоже, уже должен быть встроенный или стандартный.

Ответы [ 6 ]

70 голосов
/ 17 марта 2011

Чтобы немного рассказать об инициализации коллекции в F #, вот несколько примеров:

словарь только для чтения

dict [ (1, "a"); (2, "b"); (3, "c") ]

сек. (IEnumerable )

seq { 0 .. 99 }

список

[1; 2; 3; 4; 5]

1020 * установлено *

set [1; 2; 3; 4; 5]

массив

[| 1; 2; 3; 4; 5 |]
26 голосов
/ 17 марта 2011

Как говорит Джаред, встроенной поддержки для произвольных коллекций нет.Однако код C # является просто синтаксическим сахаром для вызовов Add методов, поэтому вы можете перевести его на:

let coll = MyCollectionType()
["One", 1; "Two", 2] |> Seq.iter coll.Add

Если вы хотите проявить фантазию, вы можете создать определение inline, чтобы упростить этоеще дальше:

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]
12 голосов
/ 17 марта 2011

Я не верю, что F # имеет явный синтаксис инициализатора коллекции. Однако обычно очень легко инициализировать коллекции F #. Например

let map = [ ("One", 1); ("Two", 2) ] |> Map.ofSeq

Добраться до коллекций BCL обычно немного сложнее, потому что они не всегда имеют удобные функции преобразования. Dictionary<TKey, TValue> работает, хотя, потому что вы можете использовать метод LINQ

let map = 
  let list = [ ("One", 1); ("Two", 2) ] 
  System.Linq.Enumerable.ToDictionary(list, fst, snd)
3 голосов
/ 18 марта 2011

Вы можете использовать то же самое:

open System.Collections.Generic

Dictionary<int, string>(dict [ (1, "a"); (2, "b"); (3, "c") ])

Приветствие.

2 голосов
/ 24 мая 2011

Отсутствие инициализатора коллекции раздражает некоторые XAML-ориентированные API, такие как Workflow 4.0, которые полагаются на инициализаторы коллекции вместо ctors, например,

new Sequence { Activities = { WriteLine { Text = "In the sequence!" } } };

В таких случаях императив .Add () неудобенпотому что значение концептуально декларативно, хотя оно технически изменчиво / обязательно.Тем не менее, не существует общего базового класса для набора всех действий, которые объявляют дочерний объект Activity: элемент «Activities» является pattern , а не интерфейсом, поэтому вы не можете просто написать обычную вспомогательную функцию, котораядобавляет детей к любой деятельности.К счастью, на помощь приходят ограничения члена F #.

Чтобы написать это:

Sequence() |> add [Sequence(DisplayName="InnerSeq"); WriteLine(Text = InArgument<_>("In the sequence!"))]

Сначала вам нужно определить встроенную вспомогательную функцию под названием "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

Это все еще не так хорошо, как синтаксис C #, но, по крайней мере, оно все еще декларативно.ИМХО, это не столько ошибка F #, сколько API-интерфейсы, ориентированные на коллекцию, но, по крайней мере, F # позволяет обойти это.

0 голосов
/ 17 марта 2011

Учитывая, что синтаксис инициализатора коллекции C # является синтаксическим сахаром для вызова .Add, и это подразумевает изменчивую коллекцию - я не уверен, что вы увидите такой синтаксис в F #. Он инициализирует все за один раз согласно ответу JaredPar или делает это вручную.

...