모듈

F# 의 컨텍스트에서 모듈 은 F# 프로그램에서 값, 형식 및 함수 값과 같은 F# 코드의 그룹화입니다. 모듈로 코드를 그룹화하면 관련 코드를 함께 유지하고, 프로그램의 이름 충돌을 방지하는 데 도움이 됩니다.

구문

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

설명

F# 모듈은 바인딩의 형식, 값, 함수 값 및 코드와 같은 F# 코드 do 구문의 그룹화입니다. 정적 멤버만 있는 CLR(공용 언어 런타임) 클래스로 구현됩니다. 모듈 선언에는 전체 파일이 모듈에 포함되는지 여부에 따라 최상위 모듈 선언과 로컬 모듈 선언의 두 가지 유형이 있습니다. 최상위 모듈 선언에는 모듈의 전체 파일이 포함됩니다. 최상위 모듈 선언은 파일의 첫 번째 선언으로만 나타날 수 있습니다.

최상위 모듈 선언 구문에서 선택적 정규화된 네임스페이스는 모듈을 포함하는 중첩된 네임스페이스 이름의 시퀀스입니다. 정규화된 네임스페이스는 이전에 선언할 필요가 없습니다.

최상위 모듈에서는 선언을 들여쓰지 않아도 됩니다. 로컬 모듈의 모든 선언을 들여쓰기해야 합니다. 로컬 모듈 선언에서 해당 모듈 선언 아래에 들여쓰기된 선언만 모듈의 일부입니다.

코드 파일이 최상위 모듈 선언 또는 네임스페이스 선언으로 시작되지 않으면 로컬 모듈을 포함한 파일의 전체 콘텐츠가 확장명 없이 파일과 이름이 같은 암시적으로 생성된 최상위 모듈의 일부가 되며 첫 글자가 대문자로 변환됩니다. 예를 들어 다음 파일을 고려합니다.

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

이 파일은 다음과 같이 작성된 것처럼 컴파일됩니다.

module Program
let x = 40

파일에 여러 모듈이 있는 경우 각 모듈에 대해 로컬 모듈 선언을 사용해야 합니다. 바깥쪽 네임스페이스가 선언된 경우 이러한 모듈은 바깥쪽 네임스페이스의 일부입니다. 바깥쪽 네임스페이스가 선언되지 않은 경우 모듈은 암시적으로 생성된 최상위 모듈의 일부가 됩니다. 다음 코드 예제에서는 여러 모듈을 포함하는 코드 파일을 보여 줍니다. 컴파일러는 암시적으로 명명 MultiplemodulesMyModule1MyModule2 된 최상위 모듈을 만들고 해당 최상위 모듈에 중첩됩니다.

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

프로젝트 또는 단일 컴파일에 여러 파일이 있거나 라이브러리를 빌드하는 경우 파일 맨 위에 네임스페이스 선언 또는 모듈 선언을 포함해야 합니다. F# 컴파일러는 프로젝트 또는 컴파일 명령줄에 파일이 하나만 있고 애플리케이션을 만드는 경우에만 모듈 이름을 암시적으로 결정합니다.

접근성 한정자는 다음 publicprivateinternal중 하나일 수 있습니다. 자세한 내용은 Access Control을 참조하세요. 기본값은 public입니다.

모듈에서 코드 참조

다른 모듈에서 함수, 형식 및 값을 참조하는 경우 정규화된 이름을 사용하거나 모듈을 열어야 합니다. 정규화된 이름을 사용하는 경우 원하는 프로그램 요소의 네임스페이스, 모듈 및 식별자를 지정해야 합니다. 다음과 같이 정규화된 경로의 각 부분을 점(.)으로 구분합니다.

Namespace1.Namespace2.ModuleName.Identifier

모듈 또는 하나 이상의 네임스페이스를 열어 코드를 간소화할 수 있습니다. 네임스페이스 및 모듈을 여는 방법에 대한 자세한 내용은 가져오기 선언: 키 open 워드를 참조하세요.

다음 코드 예제에서는 파일의 끝까지 모든 코드를 포함 하는 최상위 모듈을 보여 줍니다.

module Arithmetic

let add x y =
    x + y

let sub x y =
    x - y

동일한 프로젝트의 다른 파일에서 이 코드를 사용하려면 다음 예제와 같이 정규화된 이름을 사용하거나 함수를 사용하기 전에 모듈을 엽니다.

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

중첩된 모듈

모듈을 중첩할 수 있습니다. 내부 모듈은 외부 모듈 선언까지 들여쓰기하여 새 모듈이 아니라 내부 모듈임을 나타내야 합니다. 예를 들어 다음 두 예제를 비교합니다. 모듈 Z 은 다음 코드의 내부 모듈입니다.

module Y =
    let x = 1

    module Z =
        let z = 5

그러나 모듈 Z 은 다음 코드에서 모듈 Y 의 형제입니다.

module Y =
    let x = 1

module Z =
    let z = 5

모듈은 모듈 Z 의 다른 선언만큼 들여쓰기되지 않으므로 다음 코드의 형제 모듈이기도 Y합니다.

module Y =
        let x = 1

    module Z =
        let z = 5

마지막으로 외부 모듈에 선언이 없고 바로 뒤에 다른 모듈 선언이 오는 경우 새 모듈 선언은 내부 모듈로 간주되지만 두 번째 모듈 정의가 첫 번째 모듈 정의보다 더 멀리 들여쓰지 않으면 컴파일러에서 경고합니다.

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

경고를 제거하려면 내부 모듈을 들여쓰기합니다.

module Y =
    module Z =
        let z = 5

파일의 모든 코드를 단일 외부 모듈에 포함하도록 하고 내부 모듈을 원하는 경우 외부 모듈에는 등호가 필요하지 않으며 외부 모듈로 이동하는 내부 모듈 선언을 포함한 선언은 들여쓰기할 필요가 없습니다. 내부 모듈 선언 내의 선언은 들여쓰기해야 합니다. 다음 코드는 이 사례를 보여줍니다.

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

재귀 모듈

F# 4.1에서는 포함된 모든 코드가 상호 재귀적일 수 있도록 하는 모듈의 개념을 소개합니다. 이 작업은 .를 통해 module rec수행됩니다. module rec 형식과 모듈 간에 상호 참조 코드를 작성할 수 없는 경우의 문제가 완화될 수 있습니다. 다음은 이 예제입니다.

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

예외 DontSqueezeTheBananaException 와 클래스 Banana 는 모두 서로를 참조합니다. 또한 모듈 BananaHelpers 과 클래스 Banana 는 서로를 참조합니다. 모듈에서 키워드(keyword) 제거한 rec 경우 F#으로 RecursiveModule 표현할 수 없습니다.

이 기능은 F# 4.1이 있는 네임스페이스에서 도 가능합니다.

참고 항목