Módulos

En el contexto de F#, un módulo es una agrupación de código de F#, como valores, tipos y valores de función, en un programa de F#. Agrupar el código en módulos ayuda a mantener junto el código relacionado y a evitar conflictos de nombres en los programas.

Sintaxis

// Top-level module declaration.
module [accessibility-modifier] [qualified-namespace.]module-name
declarations
// Local module declaration.
module [accessibility-modifier] module-name =
    declarations

Comentarios

Un módulo de F# es una agrupación de construcciones de código de F#, como tipos, valores, valores de función y código en do enlaces. Se implementa como una clase de Common Language Runtime (CLR) que solo tiene miembros estáticos. Hay dos tipos de declaraciones de módulo, en función de si se incluye todo el archivo en el módulo: una declaración de módulo de nivel superior y una declaración de módulo local. Una declaración de módulo de nivel superior incluye todo el archivo del módulo. Una declaración de módulo de nivel superior solo puede aparecer como la primera declaración de un archivo.

En la sintaxis de la declaración de módulo de nivel superior, el espacio de nombres completo opcional es la secuencia de nombres de espacio de nombres anidados que contiene el módulo. El espacio de nombres completo no tiene que declararse previamente.

No es necesario aplicar sangría a las declaraciones en un módulo de nivel superior. Tiene que aplicar sangría a todas las declaraciones en módulos locales. En una declaración de módulo local, solo las declaraciones a las que se aplica sangría en esa declaración de módulo forman parte del módulo.

Si un archivo de código no comienza con una declaración de módulo de nivel superior o una declaración de espacio de nombres, todo el contenido del archivo, incluidos los módulos locales, se convierte en parte de un módulo de nivel superior creado implícitamente que tiene el mismo nombre que el archivo, sin la extensión , con la primera letra convertida a mayúsculas. Por ejemplo, considere el siguiente archivo.

// In the file program.fs.
let x = 40

Este archivo se compilaría como si se hubiera escrito de esta manera:

module Program
let x = 40

Si tiene varios módulos en un archivo, debe usar una declaración de módulo local para cada módulo. Si se declara un espacio de nombres de entrada, estos módulos forman parte del espacio de nombres que lo incluye. Si no se declara un espacio de nombres de entrada, los módulos se convierten en parte del módulo de nivel superior creado implícitamente. En el ejemplo de código siguiente se muestra un archivo de código que contiene varios módulos. El compilador crea implícitamente un módulo de nivel superior denominado Multiplemodules y MyModule1 y se MyModule2 anidan en ese módulo de nivel superior.

// In the file multiplemodules.fs.
// MyModule1
module MyModule1 =
    // Indent all program elements within modules that are declared with an equal sign.
    let module1Value = 100

    let module1Function x =
        x + 10

// MyModule2
module MyModule2 =

    let module2Value = 121

    // Use a qualified name to access the function.
    // from MyModule1.
    let module2Function x =
        x * (MyModule1.module1Function module2Value)

Si tiene varios archivos en un proyecto o en una sola compilación, o si va a compilar una biblioteca, debe incluir una declaración de espacio de nombres o una declaración de módulo en la parte superior del archivo. El compilador de F# solo determina implícitamente un nombre de módulo cuando solo hay un archivo en un proyecto o línea de comandos de compilación y está creando una aplicación.

El modificador de accesibilidad puede ser uno de los siguientes: public , , private internal . Para obtener más información, consulta Access Control. El valor predeterminado es public.

Hacer referencia a código en módulos

Al hacer referencia a funciones, tipos y valores de otro módulo, debe usar un nombre completo o abrir el módulo. Si usa un nombre completo, debe especificar los espacios de nombres, el módulo y el identificador del elemento de programa que desee. Separe cada parte de la ruta de acceso completa con un punto (.), como se muestra a continuación.

Namespace1.Namespace2.ModuleName.Identifier

Puede abrir el módulo o uno o varios de los espacios de nombres para simplificar el código. Para obtener más información sobre cómo abrir espacios de nombres y módulos, vea Declaraciones de importación: la palabra open clave.

En el ejemplo de código siguiente se muestra un módulo de nivel superior que contiene todo el código hasta el final del archivo.

module Arithmetic

let add x y =
    x + y

let sub x y =
    x - y

Para usar este código desde otro archivo en el mismo proyecto, use nombres completos o abra el módulo antes de usar las funciones, como se muestra en los ejemplos siguientes.

// Fully qualify the function name.
let result1 = Arithmetic.add 5 9
// Open the module.
open Arithmetic
let result2 = add 5 9

Módulos anidados

Los módulos se pueden anidar. Los módulos internos se deben aplicar sangría a las declaraciones de módulos externos para indicar que son módulos internos, no nuevos. Por ejemplo, compare los dos ejemplos siguientes. El Z módulo es un módulo interno en el código siguiente.

module Y =
    let x = 1

    module Z =
        let z = 5

Pero el Z módulo es un módulo relacionado con en el código Y siguiente.

module Y =
    let x = 1

module Z =
    let z = 5

El módulo también es un módulo relacionado en el código siguiente, ya que no se aplica sangría a Z otras declaraciones del módulo Y .

module Y =
        let x = 1

    module Z =
        let z = 5

Por último, si el módulo externo no tiene declaraciones y va seguido inmediatamente de otra declaración de módulo, se supone que la nueva declaración de módulo es un módulo interno, pero el compilador le advertirá si la segunda definición de módulo no tiene sangría más allá de la primera.

// This code produces a warning, but treats Z as a inner module.
module Y =
module Z =
    let z = 5

Para eliminar la advertencia, aplique sangría al módulo interno.

module Y =
    module Z =
        let z = 5

Si desea que todo el código de un archivo esté en un único módulo externo y desea módulos internos, el módulo externo no requiere el signo igual y las declaraciones, incluidas las declaraciones de módulos internos, que irán en el módulo externo no tienen que aplicar sangría. Las declaraciones dentro de las declaraciones de módulo interno tienen que aplicar sangría. En el código siguiente se muestra este caso.

// The top-level module declaration can be omitted if the file is named
// TopLevel.fs or topLevel.fs, and the file is the only file in an
// application.
module TopLevel

let topLevelX = 5

module Inner1 =
    let inner1X = 1
module Inner2 =
    let inner2X = 5

Módulos recursivos

F# 4.1 presenta la noción de módulos que permiten que todo el código contenido sea mutuamente recursivo. Esto se realiza a través de module rec . El uso de puede mitigar algunos problemas al no poder escribir código referencial mutuamente module rec entre tipos y módulos. A continuación se muestra un ejemplo de esto:

module rec RecursiveModule =
    type Orientation = Up | Down
    type PeelState = Peeled | Unpeeled

    // This exception depends on the type below.
    exception DontSqueezeTheBananaException of Banana

    type Banana(orientation : Orientation) =
        member val IsPeeled = false with get, set
        member val Orientation = orientation with get, set
        member val Sides: PeelState list = [ Unpeeled; Unpeeled; Unpeeled; Unpeeled] with get, set

        member self.Peel() = BananaHelpers.peel self // Note the dependency on the BananaHelpers module.
        member self.SqueezeJuiceOut() = raise (DontSqueezeTheBananaException self) // This member depends on the exception above.

    module BananaHelpers =
        let peel (b: Banana) =
            let flip (banana: Banana) =
                match banana.Orientation with
                | Up ->
                    banana.Orientation <- Down
                    banana
                | Down -> banana

            let peelSides (banana: Banana) =
                banana.Sides
                |> List.map (function
                             | Unpeeled -> Peeled
                             | Peeled -> Peeled)

            match b.Orientation with
            | Up ->   b |> flip |> peelSides
            | Down -> b |> peelSides

Tenga en cuenta que la DontSqueezeTheBananaException excepción y la Banana clase hacen referencia entre sí. Además, el módulo BananaHelpers y la clase también hacen referencia entre Banana sí. Esto no sería posible expresar en F# si quita la rec palabra clave del RecursiveModule módulo.

Esta funcionalidad también es posible en espacios de nombres con F# 4.1.

Vea también