モジュールとプログラム#

モジュールは、最新のFortranライブラリとアプリケーションを作成するための推奨される方法です。慣例として、1つのソースファイルには常に1つのモジュールのみを含める必要があり、モジュール名はファイルパスと一致する必要があります。大規模なプロジェクトで簡単にナビゲーションできるようにするためです。また、他のプロジェクトで依存関係として使用する場合の名前の衝突を避けるために、モジュール名の先頭にライブラリ名を付けることをお勧めします。

このようなモジュールファイルの例を次に示します。

!> Interface to TOML processing library.
!>
!> ...
module fpm_toml
  use fpm_error, only : error_t, fatal_error, file_not_found_error
  use fpm_strings, only : string_t
  use tomlf, only : toml_table, toml_array, toml_key, toml_stat, get_value, &
    & set_value, toml_parse, toml_error, new_table, add_table, add_array, &
    & toml_serializer, len
  implicit none
  private

  public :: read_package_file
  public :: toml_table, toml_array, toml_key, toml_stat, get_value, set_value
  public :: new_table, add_table, add_array, len
  public :: toml_error, toml_serializer, toml_parse

contains

  !> Process the configuration file to a TOML data structure
  subroutine read_package_file(table, manifest, error)
    !> TOML data structure
    type(toml_table), allocatable, intent(out) :: table
    !> Name of the package configuration file
    character(len=*), intent(in) :: manifest
    !> Error status of the operation
    type(error_t), allocatable, intent(out) :: error
    ! ...
  end subroutine read_package_file

end module fpm_toml

このモジュール例には、強調すべき点がいくつかあります。まず、すべてのモジュールは、モジュールの目的と内容を説明するコメントで始まります。同様に、すべての手続きは、その目的と仮引数の意図を簡単に説明するコメントで始まります。ドキュメントは、言語に関係なく、長寿命のソフトウェアを作成する上で最も重要な部分の1つです。

次に、インポート(use)とエクスポート(public)が明示的に指定されています。これにより、モジュールソースを一目で確認して、使用されている手続き、定数、および派生型を確認できます。インポートは通常、すべての手続きまたはインターフェーススコープで再インポートされるのではなく、モジュールスコープに制限されます。同様に、エクスポートは、1行にprivateステートメントを追加し、publicステートメントにすべてのエクスポートされたシンボルを明示的にリストすることによって明示的に行われます。

最後に、implicit noneステートメントはモジュール全体で機能し、各手続き内で繰り返す必要はありません。

モジュール内の変数は静的です(暗黙的に保存されます)。モジュール変数の使用は、パラメータや列挙子などの定数式に限定するか、publicではなくprotectedとしてエクスポートすることを強くお勧めします。

サブモジュールを使用すると、長い依存関係チェーンを分割し、Fortranプログラムの再コンパイルカスケードを短縮できます。また、プリプロセッサを使用せずに、特殊化された最適化された実装を提供する可能性も提供します。

Fortran標準ライブラリの例は、モジュール手続きへのインターフェースのみを定義し、実装は定義しない求積法モジュールです。

!> Numerical integration
!>
!> ...
module stdlib_quadrature
  use stdlib_kinds, only: sp, dp, qp
  implicit none
  private

  public :: trapz
  ! ...

  !> Integrates sampled values using trapezoidal rule
  interface trapz
    pure module function trapz_dx_dp(y, dx) result(integral)
      real(dp), intent(in) :: y(:)
      real(dp), intent(in) :: dx
      real(dp) :: integral
    end function trapz_dx_dp
    module function trapz_x_dp(y, x) result(integral)
      real(dp), intent(in) :: y(:)
      real(dp), intent(in) :: x(:)
      real(dp) :: integral
    end function trapz_x_dp
  end interface trapz

  ! ...
end module stdlib_quadrature

実装は、ここに示す台形積分則のような個別のサブモジュールで提供されます。

!> Actual implementation of the trapezoidal integration rule
!>
!> ...
submodule (stdlib_quadrature) stdlib_quadrature_trapz
  use stdlib_error, only: check
  implicit none

contains

  pure module function trapz_dx_dp(y, dx) result(integral)
    real(dp), intent(in) :: y(:)
    real(dp), intent(in) :: dx
    real(dp) :: integral
    integer :: n

    n = size(y)
    select case (n)
    case (0:1)
      integral = 0.0_dp
    case (2)
      integral = 0.5_dp*dx*(y(1) + y(2))
    case default
      integral = dx*(sum(y(2:n-1)) + 0.5_dp*(y(1) + y(n)))
    end select
  end function trapz_dx_dp

  ! ...
end submodule stdlib_quadrature_trapz

モジュール手続きは同じサブモジュールに実装する必要はないことに注意してください。巨大なモジュールのコンパイル負荷を軽減するために、複数のサブモジュールを使用できます。

最後に、プログラムを設定する場合、プログラム本体の実際の実装を最小限に抑えることをお勧めします。モジュールの実装を再利用することで、再利用可能なコードを作成し、プログラムユニットをそれぞれのライブラリ関数とオブジェクトへのユーザー入力の伝達に集中させることができます。