Modul

Dalam konteks F#, modul adalah pengelompokan kode F#, seperti nilai, jenis, dan nilai fungsi, dalam program F#. Mengelompokkan kode dalam modul membantu kode terkait tetap menyatu dan membantu menghindari konflik nama dalam program Anda.

Sintaks

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

Keterangan

Modul F# adalah pengelompokkan dari konstruksi kode F#, seperti tipe, nilai, nilai fungsi, dan kode dalam pengikatan do. Hal ini diimplementasikan sebagai kelas runtime bahasa umum (CLR) yang hanya memiliki anggota statis. Ada dua jenis deklarasi modul, tergantung apakah keseluruhan file disertakan dalam modul: deklarasi modul tingkat atas dan deklarasi modul lokal. Deklarasi modul tingkat atas menyertakan seluruh file di dalam modul. Deklarasi modul tingkat atas hanya dapat muncul sebagai deklarasi pertama dalam file.

Dalam sintaks untuk deklarasi modul tingkat atas, qualified-namespace opsional adalah urutan nama namespace bersarang yang berisi modul. Namespace yang memenuhi syarat tidak harus dideklarasikan sebelumnya.

Anda tidak perlu membuat indentasi deklarasi dalam modul tingkat atas. Anda harus membuat indentasi untuk semua deklarasi dalam modul lokal. Dalam deklarasi modul lokal, hanya deklarasi yang diindentasi di bawah deklarasi modul tersebut yang merupakan bagian dari modul.

Jika file kode tidak dimulai dengan deklarasi modul tingkat atas atau deklarasi namespace, seluruh konten file tersebut, termasuk modul lokal apa pun, menjadi bagian dari modul tingkat atas yang dibuat secara implisit, yang memiliki nama yang sama dengan file, tanpa ekstensi, dengan huruf pertama dikonversi menjadi huruf besar. Sebagai contoh, perhatikan file berikut.

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

File ini akan dikompilasi seolah-olah ditulis dengan cara ini:

module Program
let x = 40

Jika Anda memiliki beberapa modul dalam sebuah file, Anda harus menggunakan deklarasi modul lokal untuk setiap modul. Jika namespace penutup dideklarasikan, modul-modul ini merupakan bagian dari namespace penutup. Jika namespace penutup tidak dideklarasikan, modul-modul tersebut menjadi bagian dari modul tingkat atas yang dibuat secara implisit. Contoh kode berikut menunjukkan file kode yang berisi beberapa modul. Kompilator membuat modul tingkat atas secara implisit bernama Multiplemodules, MyModule1, dan MyModule2 yang bersarang di modul tingkat atas tersebut.

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

Jika Anda memiliki beberapa file dalam sebuah proyek atau dalam satu kompilasi, atau jika Anda sedang membangun sebuah pustaka, Anda harus menyertakan deklarasi namespace atau deklarasi modul di bagian atas file tersebut. Kompilator F# hanya menentukan nama modul secara implisit ketika hanya ada satu file dalam sebuah proyek atau baris perintah kompilasi dan Anda sedang membuat sebuah aplikasi.

Pengubah-aksesibilitas dapat berupa salah satu dari hal berikut: public, private, internal. Untuk informasi selengkapnya, lihat Kontrol Akses. Defaultnya adalah publik.

Mereferensikan Kode dalam Modul

Saat Anda mereferensikan fungsi, tipe, dan nilai dari modul lain, Anda harus menggunakan nama yang memenuhi syarat atau membuka modul. Jika Anda menggunakan nama yang memenuhi syarat, Anda harus menentukan namespace, modul, atau pengidentifikasi untuk elemen program yang Anda inginkan. Anda memisahkan setiap bagian dari jalur yang memenuhi syarat dengan tanda titik (.), sebagai berikut.

Namespace1.Namespace2.ModuleName.Identifier

Anda dapat membuka modul atau satu atau beberapa namespace untuk menyederhanakan kode. Untuk informasi selengkapnya tentang membuka namespace dan modul, lihat Deklarasi Impor: Kata Kunci open.

Contoh kode berikut menunjukkan modul tingkat atas yang berisi semua kode hingga akhir file.

module Arithmetic

let add x y =
    x + y

let sub x y =
    x - y

Untuk menggunakan kode ini dari file lain yang berada di dalam proyek yang sama, Anda menggunakan nama yang memenuhi syarat atau Anda membuka modul sebelum menggunakan fungsi, seperti yang ditunjukkan dalam contoh berikut.

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

Modul Bersarang

Modul dapat bersarang. Modul dalam harus diindentasi sejauh deklarasi modul luar untuk menunjukkan bahwa mereka adalah modul dalam, bukan modul baru. Misalnya, bandingkan dua contoh berikut. Modul Z adalah modul dalam pada kode berikut.

module Y =
    let x = 1

    module Z =
        let z = 5

Tetapi, modul Z adalah saudara dari modul Y dalam kode berikut.

module Y =
    let x = 1

module Z =
    let z = 5

Modul Z juga merupakan modul saudara dalam kode berikut, karena tidak diindentasi sejauh deklarasi lain dalam modul Y.

module Y =
        let x = 1

    module Z =
        let z = 5

Terakhir, jika modul luar tidak memiliki deklarasi dan langsung diikuti oleh deklarasi modul lain, deklarasi modul baru akan diasumsikan sebagai modul dalam, tetapi kompilator akan memperingatkan Anda jika definisi modul kedua tidak diindentasi lebih jauh dari yang pertama.

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

Untuk menghilangkan peringatan, inden modul dalam.

module Y =
    module Z =
        let z = 5

Jika Anda ingin semua kode di dalam sebuah file berada dalam satu modul luar dan Anda ingin modul dalam, modul luar tidak membutuhkan tanda sama dengan, dan deklarasi, termasuk deklarasi modul dalam apa pun yang akan masuk ke modul luar tidak harus diindentasi. Deklarasi di dalam deklarasi modul dalam harus diindentasi. Kode berikut menunjukkan kasus ini.

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

Modul rekursif

F# 4.1 memperkenalkan gagasan modul yang memungkinkan semua kode yang dimuat saling rekursif. Ini dilakukan melalui module rec. Penggunaan module rec dapat mengurangi rasa sakit karena tidak dapat menulis kode referensial timbal balik antara jenis dan modul. Berikut ini adalah contohnya:

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

Perhatikan bahwa pengecualian DontSqueezeTheBananaException dan kelas Banana keduanya saling merujuk. Selain itu, modul BananaHelpers dan kelas Banana juga saling merujuk. Hal ini tidak mungkin untuk diungkapkan dalam F# jika Anda menghapus kata kunci rec dari modul RecursiveModule.

Kemampuan ini juga dimungkinkan dalam Namespace dengan F# 4.1.

Lihat juga