AutoOpen attribute in F#

ⅰ亾dé卋堺 提交于 2019-11-30 06:53:22

问题


What is the recommended doctrine for using the AutoOpen attribute ?

(This question is probably is in continuation to when to use module function VS static function on similarly named type )

Expert F# states that "This can be useful when you’re defining ad hoc top-level operators and functions:"

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 ?


回答1:


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. 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):

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. I think the same pattern is used with various math libraries (where you also want to export simple-named functions.)

For modules (e.g. 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.




回答2:


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.).




回答3:


A little late to the party, but I wanted to add another usage.

I tend to use [<AutoOpen>] to expose types within a namespace.

// 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. and Intellisense will show it. Much in the same way that types such as List are used in practice.

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.

I much prefer this solution to augmenting types with static members.



来源:https://stackoverflow.com/questions/12977466/autoopen-attribute-in-f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!