Modules

In de context van F# is een module een groepering van F#-code, zoals waarden, typen en functiewaarden, in een F#-programma. Het groeperen van code in modules helpt gerelateerde code bij elkaar te houden en helpt naamconflicten in uw programma te voorkomen.

Syntaxis

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

Opmerkingen

Een F#-module is een groepering van F#-codeconstructies, zoals typen, waarden, functiewaarden en code in do bindingen. Het wordt geïmplementeerd als een CLR-klasse (Common Language Runtime) met alleen statische leden. Er zijn twee typen moduledeclaraties, afhankelijk van of het hele bestand is opgenomen in de module: een moduledeclaratie op het hoogste niveau en een lokale moduledeclaratie. Een moduledeclaratie op het hoogste niveau bevat het hele bestand in de module. Een moduledeclaratie op het hoogste niveau kan alleen worden weergegeven als de eerste declaratie in een bestand.

In de syntaxis voor de declaratie van de module op het hoogste niveau is de optionele gekwalificeerde naamruimte de reeks geneste naamruimtenamen die de module bevat. De gekwalificeerde naamruimte hoeft niet eerder te worden gedeclareerd.

U hoeft declaraties niet te laten inspringen in een module op het hoogste niveau. U moet alle declaraties in de lokale modules laten inspringen. In een lokale moduledeclaratie maken alleen de declaraties die zijn ingesprongen onder die moduledeclaratie deel uit van de module.

Als een codebestand niet begint met een declaratie van een module op het hoogste niveau of een naamruimtedeclaratie, wordt de hele inhoud van het bestand, inclusief lokale modules, onderdeel van een impliciet gemaakte module op het hoogste niveau met dezelfde naam als het bestand, zonder de extensie, met de eerste letter geconverteerd naar hoofdletters. Denk bijvoorbeeld aan het volgende bestand.

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

Dit bestand wordt gecompileerd alsof het op deze manier is geschreven:

module Program
let x = 40

Als u meerdere modules in een bestand hebt, moet u voor elke module een lokale moduledeclaratie gebruiken. Als een omsluitende naamruimte wordt gedeclareerd, maken deze modules deel uit van de omsluitende naamruimte. Als een ingesloten naamruimte niet wordt gedeclareerd, worden de modules onderdeel van de impliciet gemaakte module op het hoogste niveau. In het volgende codevoorbeeld ziet u een codebestand dat meerdere modules bevat. De compiler maakt impliciet een module op het hoogste niveau met de naam Multiplemodulesen MyModule2MyModule1 is genest in die module op het hoogste niveau.

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

Als u meerdere bestanden in een project of in één compilatie hebt of als u een bibliotheek bouwt, moet u boven aan het bestand een naamruimtedeclaratie of moduledeclaratie opnemen. De F#-compiler bepaalt alleen impliciet een modulenaam wanneer er slechts één bestand in een project of compilatie-opdrachtregel staat en u een toepassing maakt.

De toegankelijkheidsaanpassing kan een van de volgende zijn: public, private, internal. Zie Toegangsbeheer voor meer informatie. De standaardwaarde is openbaar.

Verwijzen naar code in modules

Wanneer u verwijst naar functies, typen en waarden uit een andere module, moet u een gekwalificeerde naam gebruiken of de module openen. Als u een gekwalificeerde naam gebruikt, moet u de naamruimten, de module en de id voor het gewenste programma-element opgeven. U scheidt elk deel van het gekwalificeerde pad als volgt met een punt (.).

Namespace1.Namespace2.ModuleName.Identifier

U kunt de module of een of meer naamruimten openen om de code te vereenvoudigen. Zie Declaraties importeren: het open trefwoord voor meer informatie over het openen van naamruimten en modules.

In het volgende codevoorbeeld ziet u een module op het hoogste niveau die alle code tot het einde van het bestand bevat.

module Arithmetic

let add x y =
    x + y

let sub x y =
    x - y

Als u deze code uit een ander bestand in hetzelfde project wilt gebruiken, gebruikt u gekwalificeerde namen of opent u de module voordat u de functies gebruikt, zoals wordt weergegeven in de volgende voorbeelden.

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

Geneste modules

Modules kunnen worden genest. Binnenste modules moeten worden ingesprongen tot buitenste moduledeclaraties om aan te geven dat het interne modules zijn, niet nieuwe modules. Vergelijk bijvoorbeeld de volgende twee voorbeelden. Module Z is een interne module in de volgende code.

module Y =
    let x = 1

    module Z =
        let z = 5

Maar module Z is een niveau van hetzelfde niveau als module Y in de volgende code.

module Y =
    let x = 1

module Z =
    let z = 5

Module Z is ook een module op hetzelfde niveau in de volgende code, omdat deze niet is ingesprongen voor andere declaraties in de module Y.

module Y =
        let x = 1

    module Z =
        let z = 5

Als de buitenste module geen declaraties heeft en onmiddellijk wordt gevolgd door een andere moduledeclaratie, wordt ervan uitgegaan dat de nieuwe moduledeclaratie een interne module is, maar de compiler waarschuwt u als de tweede moduledefinitie niet verder is ingesprongen dan de eerste.

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

Als u de waarschuwing wilt elimineren, laat u de binnenste module inspringen.

module Y =
    module Z =
        let z = 5

Als u wilt dat alle code in een bestand zich in één buitenste module bevindt en u interne modules wilt, is voor de buitenste module geen gelijkteken vereist en hoeven de declaraties, inclusief eventuele declaraties van interne modules, die in de buitenste module gaan, niet ingesprongen te zijn. Declaraties binnen de declaraties van de binnenste module moeten worden ingesprongen. In de volgende code ziet u dit geval.

// 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

Recursieve modules

F# 4.1 introduceert het begrip modules waarmee alle ingesloten code wederzijds recursief kan zijn. Dit gebeurt via module rec. Het gebruik van module rec kan sommige pijn verlichten bij het niet kunnen schrijven van wederzijds referentiële code tussen typen en modules. Hier volgt een voorbeeld van:

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

Houd er rekening mee dat de uitzondering DontSqueezeTheBananaException en de klasse Banana beide naar elkaar verwijzen. Daarnaast verwijzen de module BananaHelpers en de klasse Banana ook naar elkaar. Dit zou niet mogelijk zijn om in F# uit te drukken als u het rec trefwoord uit de RecursiveModule module hebt verwijderd.

Deze mogelijkheid is ook mogelijk in naamruimten met F# 4.1.

Zie ook