我可以从Fortran中的函数返回“函数句柄”吗?

时间:2019-10-13 04:41:27

标签: fortran

我正在将一些MATLAB代码移植到Fortran,并且需要复制scatteredInterpolant的功能。 splitInterpolant会获取一组采样点并返回本质上是一个函数句柄,该函数句柄可以获取一个新点并返回一个插值。

我可以通过返回带有“ interpolate”函数或类似函数的派生类型来做到这一点,但我想使Fortran尽可能接近原始MATLAB。有没有一种方法可以在运行时生成一个函数并返回从另一个函数访问该函数的某种方式?

2 个答案:

答案 0 :(得分:2)

您可能会以面向对象的方式实现所需的行为,

module Interpolation_mod

    use iso_fortran_env, only: RK => real64
    implicit none

    type :: Interpolation_type
        real(RK)              :: linearInterpSlope, linearInterpIntercept
        real(RK), allocatable :: X(:), Value(:)
    contains
        procedure, pass :: functionHandle
    end type Interpolation_type

    interface Interpolation_type
        module procedure :: scatteredInterpolant
    end interface Interpolation_type

contains

    ! creates an Interpolation object and sets up all the essentials of calling functionHandle
    function scatteredInterpolant(X,Value) result(InterpolationObject)
        implicit none
        real(RK), intent(in)        :: X(2), Value(2)
        type(Interpolation_type)    :: InterpolationObject
        InterpolationObject%X = X
        InterpolationObject%Value = Value
        InterpolationObject%linearInterpSlope = ( Value(2) - Value(1) ) / (X(2) - X(1))
        InterpolationObject%linearInterpIntercept = Value(1) - InterpolationObject%linearInterpSlope * X(1)
    end function scatteredInterpolant

    ! equivalent of MATLAB functionHandle
    function functionHandle(InterpolationObject,x) result(functionValue)
        implicit none
        class(Interpolation_type), intent(in)   :: InterpolationObject
        real(RK), intent(in)                    :: x
        real(RK)                                :: functionValue
        if ( x < InterpolationObject%X(1) .or. x > InterpolationObject%X(2) ) then
            write(*,"(A)") "This is interpolation, not extrapolation."
            error stop
        else
            functionValue = InterpolationObject%linearInterpSlope * x + InterpolationObject%linearInterpIntercept
        end if
    end function functionHandle

end module Interpolation_mod

program test_Interpolation
use Interpolation_mod, only: RK, Interpolation_type
implicit none
type(Interpolation_type) :: Interpolation
Interpolation = Interpolation_type( X = [0._RK,1._RK], Value = [0._RK,1._RK] )
write(*,"(*(g0,:,' '))") "Interpolation(", 0.5, ") =", Interpolation%functionHandle(0.5_RK)
end program test_Interpolation
C:\> ifort main.f90 -o main.exe

Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 19.0.4.245 Build 20190417
Copyright (C) 1985-2019 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.22.27905.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:main.exe
-subsystem:console
main.obj

C:\> main.exe
Interpolation( .5000000 ) = .5000000000000000

答案 1 :(得分:0)

您实际上想要的是某种closure。在Fortran中是不可能的。另外,Fortran语法不允许直接调用派生类型。您将需要建议的间接方法之一。您还可以使用一个模块,但是只允许这样的关闭/函数的一个实例。

Fortran确实允许返回aa函数指针,但这对于您所描述的还不够。另请参见Fortran minimization of a function with additional arguments中的相关技术以及“相关”下链接到的函数。事实证明,它不能完全满足您的需求,但与之相关。