简体   繁体   English

F#中的AutoOpen属性

[英]AutoOpen attribute in F#

What is the recommended doctrine for using the AutoOpen attribute ? 使用AutoOpen属性的推荐原则是什么?

(This question is probably is in continuation to when to use module function VS static function on similarly named type ) (这个问题可能是在类似命名类型上何时使用模块功能VS静态功能的延续)

Expert F# states that "This can be useful when you're defining ad hoc top-level operators and functions:" 专家F#指出“当你定义ad hoc顶级运算符和函数时,这可能很有用:”

So this seems to be here to kind of diminish the module role in the code organization, when you technically need one to write the code but you remove its existence from a client perspective. 因此,这似乎可以减少代码组织中的模块角色,当您在技术上需要编写代码但从客户端角度删除它的存在时。

Is there something else ? 还有别的吗? When do you use it ? 你什么时候使用它?

I think the main use for the AutoOpen attribute is when you want to make some let-bound values available when the user of your library opens a namespace. 我认为AutoOpen属性的主要用途是当您的库用户打开命名空间时,您想要使一些let-bound值可用。 This is where the attribute is very useful, because I think libraries should generally export all definitions in namespaces , but for some purposes you need to export values and values cannot be defined inside a namespace. 这是属性非常有用的地方,因为我认为库通常应该在命名空间中导出所有定义,但出于某些目的,您需要导出值,并且不能在命名空间内定义值。

Here is an example from F# async extensions which defines a computation builder and thus it needs to export asyncSeq value (but at the same time, all functionality is wrapped in a namespace): 以下是F#异步扩展的示例,它定义了一个计算构建器,因此需要导出asyncSeq值(但同时,所有功能都包含在命名空间中):

namespace FSharp.Async

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

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

The user of the library can just write open FSharp.Async and they will see asyncSeq . 该库的用户只需编写open FSharp.Async ,他们就会看到asyncSeq I think the same pattern is used with various math libraries (where you also want to export simple-named functions.) 我认为相同的模式用于各种数学库(您还希望导出简单命名的函数。)

For modules (eg List and Seq ), I think most of the people do not use open and access the functions via a module name (such as List.map ), so although you can use this for nested modules, I have not seen that as frequently. 对于模块(例如ListSeq ),我认为大多数人不使用open并通过模块名称(例如List.map )访问函数,所以尽管你可以将它用于嵌套模块,但我还没有看到经常。

It can be used to organize a module into sub-modules but present a unified/single-module view externally: 它可用于将模块组织到子模块中,但在外部呈现统一/单模块视图:

module Outer =

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

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

open Outer

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

FParsec does this: open FParsec opens all sub-modules ( Primitives , CharParsers , etc.). FParsec执行此操作: open FParsec打开所有子模块( PrimitivesCharParsers等)。

A little late to the party, but I wanted to add another usage. 派对有点晚了,但我想添加另一种用法。

I tend to use [<AutoOpen>] to expose types within a namespace. 我倾向于使用[<AutoOpen>]来公开命名空间中的类型。

// SlimSql\Types.fs
namespace SlimSql

[<AutoOpen>]
module Types =

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

Then I can attach functions to the same type name without getting a compiler error that the name is already in use. 然后我可以将函数附加到相同的类型名称,而不会得到名称已被使用的编译器错误。

// SlimSql\SqlOperation.fs
namespace SlimSql

module SqlOperation =

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

    let wrapInTransaction operation =
        ...

Then everything is nicely packaged up with the same name in consuming code. 然后在消费代码中使用相同的名称对所有内容进行了很好的打包。 So when the user is looking for a behavior on SqlOperation data, they can naturally find it by typing SqlOperation. 因此,当用户在SqlOperation数据上查找行为时,他们可以通过键入SqlOperation.自然找到它SqlOperation. and Intellisense will show it. 和Intellisense将展示它。 Much in the same way that types such as List are used in practice. 与实际使用List等类型的方式大致相同。

open SlimSql

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

The SlimSql.Types module can also be opened by itself to access only the types for composition with other types. SlimSql.Types模块也可以单独打开,以仅访问其他类型的合成类型。

I much prefer this solution to augmenting types with static members. 我更喜欢这个解决方案来增加静态成员的类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM