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

Имя кортежей/анонимных типов в F #?

в С# вы можете делать такие вещи, как:

var a = new {name = "cow", sound = "moooo", omg = "wtfbbq"};

и в Python вы можете делать такие вещи, как

a = t(name = "cow", sound = "moooo", omg = "wtfbbq")

Не по умолчанию, конечно, но тривиально реализовать класс t, который позволяет вам это сделать. Infact Я сделал именно это, когда я работал с Python и нашел его невероятно удобным для небольших контейнеров с отбросами, где вы хотите иметь доступ к компонентам по имени, а не по индексу (который легко смешивать).

Помимо этой детали, они в основном идентичны кортежам в нише, которую они обслуживают.

В частности, я сейчас смотрю на этот код С#:

routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

а F # эквивалентно

type Route = { 
    controller : string
    action : string
    id : UrlParameter }

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    { controller = "Home"; action = "Index"; id = UrlParameter.Optional } // Parameter defaults
  )

Это как многословный, так и повторяющийся, не говоря уже о довольно раздражающем. Как близко вы можете получить такой синтаксис в F #? Я не против прыгать через некоторые обручи (даже пылающие обручи!) Сейчас, если это означает, что это даст мне что-то полезное для DRY-кода, подобного этому.

4b9b3361

Ответ 1

Мне легче сделать

let route = routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}" // URL with parameters
    )
route.Defaults.Add("controller", "Home")
route.Defaults.Add("action", "Index")

или

[ "controller", "Home"
  "action", "Index" ]
|> List.iter route.Defaults.Add

В F # я бы избегал вызывать перегрузки, которые принимают анонимные типы, так как я бы избегал вызова метода F #, принимающего FSharpList из С#. Это специфические для языка функции. Обычно существует языковая агностическая перегрузка/обходной путь.

ИЗМЕНИТЬ

Просто посмотрел на документы - вот еще один способ сделать это

let inline (=>) a b = a, box b

let defaults = dict [
  "controller" => "Home"
  "action"     => "Index" 
]
route.Defaults <- RouteValueDictionary(defaults)

Ответ 2

Вы не можете создавать "анонимные записи" в F # - при использовании типов вы можете использовать анонимные кортежи, но не носите метки, или вы можете использовать записи, которые должны быть объявлены заранее, и иметь метки:

// Creating an anonymous tuple
let route = ("Home", "Index", UrlParameter.Optional)

// Declaration and creating of a record with named fields
type Route = { controller : string; action : string; id : UrlParameter } 
let route = { controller = "Home"; action = "Index"; id = UrlParameter.Optional } 

Технически проблема с анонимными записями заключается в том, что их нужно будет определять как фактические классы где-то (для среды выполнения .NET требуется тип), но если компилятор помещает их в каждую сборку, тогда две анонимные записи с такими же членами могут быть разными, если они были определены в разных сборках.

Честно говоря, я думаю, что приведенный вами пример - это просто плохое дизайнерское решение в ASP.NET - это неправильное использование определенной функции С# для выполнения чего-то, для которого оно не было разработано. Возможно, это не так плохо, как , но это все еще странно. Библиотека принимает анонимный тип С#, но использует ее как словарь (т.е. Использует ее как хороший способ создания пар ключ-значение, потому что свойства, которые вам нужно указать, являются динамическими).

Итак, если вы используете ASP.NET из F #, вероятно, проще использовать альтернативный подход, в котором вам не нужно создавать записи - если ASP.NET API предоставляет некоторую альтернативу (как показывает Дэниэл, там это лучший способ написать это).

Ответ 3

OP не описывает наилучшее использование анонимного типа. Они лучше всего используются при использовании LINQ для сопоставления с произвольным классом. Например:

var results = context.Students
              .Where(x => x.CourseID = 12)
              .Select(x => new { 
                 StudentID = x.ID, 
                 Name = x.Forename + " " + x.Surname
              });

Я знаю, что это можно сделать, указав новый тип записи, но тогда у вас есть два места для поддержки кода: (1) определение типа записи (2), в котором вы его использовали.

Вместо этого он может быть выполнен с помощью кортежа, но для доступа к отдельным полям вы должны использовать синтаксис деконструкции (studentId, name) все время. Это становится громоздким, если у вас есть 5 предметов в кортеже. Я бы предпочел ввести x и нажать точку, и intellisense сообщит мне, какие поля доступны.

Ответ 4

Теперь в F # 4.6 (превью) у нас есть анонимные записи

Таким образом, мы можем иметь этот синтаксис кода:

let AwesomeAnonymous = {|  ID = Guid.NewGuid()
                           Name = "F#"
                        |}

AwesomeAnonymous.Name |> Debug.WriteLine

Он также поддерживается в Visual Studio Intellisense: Screenshot

Таким образом, этот код может быть таким:

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    {| controller = "Home"; action = "Index"; id = UrlParameter.Optional |} // Parameter defaults
  )

Смотрите также: Анонс F # 4.6 Предварительный просмотр

Ответ 5

Здесь я беру конфигурацию маршрута веб-проекта по умолчанию:

module RouteConfig =

    open System.Web.Mvc
    open System.Web.Routing

    let registerRoutes (routes: RouteCollection) =

        routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

        /// create a pair, boxing the second item
        let inline (=>) a b = a, box b

        /// set the Defaults property from a given dictionary
        let setDefaults defaultDict (route : Route) =  
            route.Defaults <- RouteValueDictionary(defaultDict)

        routes.MapRoute(name="Default", url="{controller}/{action}/{id}")
        |> setDefaults (dict ["controller" => "Home" 
                              "action" => "Index" 
                              "id" => UrlParameter.Optional])

Ответ 6

Как указал Тони в своем ответе, это не намного лучше, чем в F # 4.6. Тестируя аналогичный пример с использованием .NET Core SDK 3.0.100-preview4-011158, я смог продемонстрировать использование новой функции анонимной записи. Что касается метода RouteMap, я не знаю, какие типы значений принимает этот API, но я подозреваю, что приведенный ниже пример будет работать.

Ex.

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    {| controller = "Home"; action = "Index"; id = UrlParameter.Optional |} // Parameter defaults
  )

Обратите внимание на использование | характер внутри фигурных скобок. Это то, что сейчас отличает обычные записи от анонимных записей в F #.

Что касается вашего другого примера, возможно, пример F # теперь будет выглядеть так, как показано ниже.

let a = {| name = "cow"; sound = "moooo"; omg = "wtfbbq" |}