将一个Fortran模块拆分成多个文件

3
我试图添加转换函数以在不同衍生类型之间进行转换,我希望它们是第一个派生类型的函数,并返回另一个派生类型。只要它们在同一文件和模块中,这没有问题。但是,我真的希望它们能够分成多个文件,否则将会是一个非常大的文件。由于Fortran的依赖性和名称空间的缺乏,我无法弄清楚如何做到这一点。
是否有办法实现这一点?
以下是我想将其分成两个文件的示例(每个派生类型一个文件)。
Module ConversionStuff
  implicit none

  type A_T
    real :: a, b, c
  contains
    procedure :: toX => a_toX
  end type A_T

  type X_T
    real :: x, y, z
  contains
    procedure :: toA => x_toA
  end type X_T

  contains

  function a_toX(this) result(x)

     class(A_T), intent(inout) :: this
     type(X_T) :: x

     x%x = this%a * 2
     x%y = this%b * 2
     x%z = this%c * 2

  end function a_toX

  function x_toA(this) result(a)

     class(X_T), intent(inout) :: this
     type(A_T) :: a

     a%a = this%x * 0.5
     a%b = this%y * 0.5
     a%c = this%z * 0.5

  end function x_toA

End Module ConversionStuff

如果有打字错误,我很抱歉。在这台计算机上,我没有简单的方法来编译Fortran。


3
你了解子模块吗? - francescalus
我目前还没有带有该功能的编译器(希望很快能有)。虽然我并不指望这样就能解决问题。我可能错误地假设子模块仍将单独编译,因此会产生循环依赖。 - TrippLamb
我问这个问题并不是因为我认为它们可以解决你的问题,而是想知道你是否已经排除了它们。如果你已经排除了它们,那么进一步思考就没有意义了。 - francescalus
我并没有排除这种可能,但我并不认为它会解决问题。 - TrippLamb
2个回答

2

在当前的语言中,通过子模块很容易处理这个问题 - 两种类型定义与“共享”独立模块过程的接口一起放入祖先模块中,然后将过程定义根据需要分割到子模块中。

MODULE ConversionStuff
  IMPLICIT NONE
  TYPE :: A_T
    REAL :: a, b, c
  CONTAINS
    PROCEDURE :: toX => a_toX
  END TYPE A_T
  TYPE :: X_T
    REAL :: x, y, z
  CONTAINS
    PROCEDURE :: toA => x_toA
  END TYPE x, y, z
  INTERFACE
    MODULE FUNCTION a_toX(this) RESULT(x)
      IMPLICIT NONE
      CLASS(A_T), INTENT(IN) :: this
      TYPE(X_T) :: x
    END FUNCTION a_toX
    MODULE FUNCTION x_toA(this) RESULT(a)
      IMPLICIT NONE
      CLASS(X_T), INTENT(IN) :: this
      TYPE(A_T) :: a
    END FUNCTION x_toA
  END INTERFACE
END MODULE ConversionStuff

SUBMODULE (ConversionStuff) Procedures_for_X
  IMPLICIT NONE
CONTAINS
  MODULE PROCEDURE a_toX
    x%x = this%a * 2
    x%y = this%b * 2
    x%z = this%c * 2
  END PROCEDURE a_toX
END SUBMODULE Procedures_for_X
...

在Fortran 2008之前,有时您可以使用一种替代方法来模拟上述过程 - 实现过程放在一个单独编译的外部程序集中,该程序集使用模块。需要注意的是,外部过程不得具有其自身接口的可见性。
MODULE ConversionStuff
  IMPLICIT NONE
  TYPE :: A_T
    REAL :: a, b, c
  CONTAINS
    PROCEDURE :: toX => a_toX
  END TYPE A_T
  TYPE :: X_T
    REAL :: x, y, z
  CONTAINS
    PROCEDURE :: toA => x_toA
  END TYPE x, y, z
  INTERFACE
    FUNCTION a_toX(this) RESULT(x)
      IMPORT :: A_T
      IMPORT :: X_T
      IMPLICIT NONE
      CLASS(A_T), INTENT(IN) :: this
      TYPE(X_T) :: x
    END FUNCTION a_toX
    FUNCTION x_toA(this) RESULT(a)
      IMPORT :: A_T
      IMPORT :: X_T
      IMPLICIT NONE
      CLASS(X_T), INTENT(IN) :: this
      TYPE(A_T) :: a
    END FUNCTION x_toA
  END INTERFACE
  PRIVATE :: a_toX
  PRIVATE :: x_toA
END MODULE ConversionStuff

FUNCTION A_toX(this) RESULT(x)
  USE ConversionStuff
  IMPLICIT NONE
  CLASS(A_T), INTENT(IN) :: this
  TYPE(X_T) :: x
  ...etc...
END FUNCTION A_toX

对于这种第二种方法,Fortran的可访问性属性(PUBLIC和PRIVATE)存在使用限制。

请注意,该问题与命名空间无关,因为通常定义的概念并不涉及此问题。


我很感激。我会尝试第二个建议,并在获得它们的访问权限后使用子模块。对于回复慢,我感到抱歉。 - TrippLamb
我可以看出在某些程序很长的情况下这会有所帮助,但对于一堆小而简单的转换函数来说,似乎为接口所需的额外代码比仅将所有内容保留在单个文件中更糟糕。我有什么遗漏吗? - TrippLamb
1
实际上并没有“额外的代码” - 你只需要将接口与实现分开。你可以将函数分成任意数量的文件。请参阅https://software.intel.com/en-us/blogs/2015/07/07/doctor-fortran-in-we-all-live-in-a-yellow-submodule,了解更多相关信息。 - Steve Lionel

0

在做其他事情后,我在将近两个月后回来发现了一些我认为对于这个特定用途更简单和优雅的东西。我将保留先前接受的答案,因为它确实回答了问题,但这是一种替代方法。

它使用了include关键字。直到现在我才明白,它不会编译包含的文件,直到它正在编译包含文件。也许有些我不理解的地方,但对于我只想将单个文件拆分成多个文件以使其不至于过大的情况,我认为这种方法值得权衡,尽管它不是一个模块。如果我漏掉了什么,请告诉我。

我的解决方案如下。

Module ConversionStuff
  implicit none

  type A_T
    real :: a, b, c
  contains
    procedure :: toX => a_toX
  end type A_T

  type X_T
    real :: x, y, z
  contains
    procedure :: toA => x_toA
  end type X_T

  contains

  include "A.f90"
  include "X.f90"

End Module ConversionStuff

A.f90

function a_toX(this) result(x)

    class(A_T), intent(inout) :: this
    type(X_T) :: x

    x%x = this%a * 2
    x%y = this%b * 2
    x%z = this%c * 2

end function a_toX

X.f90

function x_toA(this) result(a)

    class(X_T), intent(inout) :: this
    type(A_T) :: a

    a%a = this%x * 0.5
    a%b = this%y * 0.5
    a%c = this%z * 0.5

 end function x_toA

1
这个问题在这个网站上已经讨论了很多次,但是关于它是否真的更加简单和优雅的观点却因人而异。 - Vladimir F Героям слава

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接