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

Атрибут AutoOpen в F #

Какова рекомендуемая доктрина для использования атрибута AutoOpen?

(Этот вопрос, вероятно, находится в продолжении когда использовать функцию VS-функции VS статической функции аналогично именованного типа)

Эксперт F # заявляет, что "это может быть полезно, когда вы определяете операторы ad hoc верхнего уровня и функции: "

Итак, это похоже на то, чтобы уменьшить роль модуля в организации кода, когда вам технически нужно написать код, но вы удаляете его существование с точки зрения клиента.

Есть ли что-то еще? Когда вы его используете?

4b9b3361

Ответ 1

Я думаю, что основное использование атрибута AutoOpen - это когда вы хотите сделать некоторые допустимые значения доступными, когда пользователь вашей библиотеки открывает пространство имен. Здесь атрибут очень полезен, потому что я думаю, что библиотеки обычно должны экспортировать все определения в пространствах имен, но для некоторых целей вам нужно экспортировать значения, а значения не могут быть определены внутри пространства имен.

Вот пример из F # async extensions, который определяет построитель вычислений и, следовательно, ему нужно экспортировать значение asyncSeq (но при этом время, вся функциональность завернута в пространство имен):

namespace FSharp.Async

type AsyncSeq<'T> = (* ... *)
type AsyncSeqBuilder() = (* ... *)

[<AutoOpen>]
module GlobalValues = 
  let asyncSeq = AsyncSeqBuilder()

Пользователь библиотеки может просто написать open FSharp.Async, и они будут видеть asyncSeq. Я думаю, что тот же шаблон используется с различными математическими библиотеками (где вы также хотите экспортировать простые имена функций.)

Для модулей (например, List и Seq) я думаю, что большинство людей не используют open и получают доступ к функциям через имя модуля (например, List.map), поэтому, хотя вы можете использовать это для вложенных модулей я не видел это так часто.

Ответ 2

Его можно использовать для организации модуля в подмодулях, но он представляет собой унифицированный/одномодовый вид снаружи:

module Outer =

  [<AutoOpen>]
  module Inner1 =
    let f1() = ()

  [<AutoOpen>]
  module Inner2 =
    let f2() = ()

open Outer

let x = f1()
let y = f2()

FParsec делает следующее: open FParsec открывает все подмодули (Primitives, CharParsers и т.д.).

Ответ 3

Немного опоздал на вечеринку, но я хотел добавить еще одно использование.

Я склонен использовать [<AutoOpen>] для предоставления типов в пространстве имен.

// SlimSql\Types.fs
namespace SlimSql

[<AutoOpen>]
module Types =

    type SqlOperation =
        {
            Statement : string
            Parameters : SqlParam list
        }

Затем я могу прикрепить функции к одному и тому же имени типа без получения ошибки компилятора, поскольку это имя уже используется.

// SlimSql\SqlOperation.fs
namespace SlimSql

module SqlOperation =

    let merge (operations : SqlOperation list) : SqlOperation =
        ...

    let wrapInTransaction operation =
        ...

Тогда все хорошо упаковано с тем же именем в потреблении кода. Поэтому, когда пользователь ищет поведение в данных SqlOperation, он может найти его, набрав SqlOperation. и Intellisense покажет это. Почти так же, как на практике используются такие типы, как List.

open SlimSql

let operations =
    [
        sql "INSERT INTO ...." [ p "@Value" 123; ... ]
        ...
    ]
let writeOp =
    operations
    |> SqlOperation.merge
    |> SqlOperation.wrapInTransaction

Модуль SlimSql.Types также можно открыть сам по себе, чтобы получить доступ только к типам композиции с другими типами.

Я предпочитаю это решение для дополнения типов статическими членами.