Подтвердить что ты не робот

Синтаксис инициализатора коллекции F #

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

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

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

4b9b3361

Ответ 1

Как говорит Джаред, для любых коллекций нет встроенной поддержки. Однако код С# является просто синтаксическим сахаром для вызовов методов 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]

Ответ 2

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

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

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

seq (IEnumerable <T> )

seq { 0 .. 99 }

список

[1; 2; 3; 4; 5]

набор

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

массив

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

Ответ 3

Я не верю, что 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)

Ответ 4

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

open System.Collections.Generic

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

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

Ответ 5

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

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

В таких случаях императив .Add() неудобен, потому что значение концептуально декларативно, даже если оно технически изменчиво/императивно. Однако нет общего базового класса для набора всех действий, объявляющих дочерний действия: член "Activities" является шаблоном, а не интерфейсом, поэтому вы не можете просто написать нормальную вспомогательную функцию, которая добавляет детей к любой активности. К счастью, ограничения членов 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

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

Ответ 6

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