假设我想将一个函数传递给另一个函数f1(f2(k, g, x), other, junk)
(f1
定义为f1(func, other, junk)
,它涉及表达式,如func(other)
)。进一步假设这两个函数都包含在第三个函数f3(k, g)
中。通过调用andf3(k, g)
的一些值,真的不再是三个变量的函数了,是吗?它只是since的函数,现在是常量。所以我想知道是否有某种方式可以说“看,你不知道我定义你的时候是什么,但现在你知道了,因为我告诉了他们是什么,所以你可以考虑自己作为 的函数,所以当我把你传给k
g
f2
x
k
g
f2
k
g
f3
x
f1
,它看到并使用只有一个变量的函数。”
2 回答
我认为您正在寻找的东西有时被称为“函子/函数对象”或 lambda 表达式 - 以一种可以用更少的参数调用它的方式包装带有多个参数的过程的能力(指定缺少的参数通过其他方式)。
在 Fortran 77 中,这通常通过在公共块的幕后传递“缺失”参数来近似。Fortran 90/95 通过让您使用模块变量来改变这一点。这两种方法都有一个缺点,即一次只能存在一个包装过程的实例,尽管出于其他原因,在公共块上使用模块是一个非常优越的选择。
Fortran 2003 引入了其他选项 - 使用派生类型和类型扩展。这需要更改 f1 的代码 - 该函数接受一个多态参数,而不是一个虚拟过程参数,其声明的类型具有一个绑定,该绑定具有与 f1 的前一个参数类似的接口,但带有一个传递的对象。然后,缺少的参数将成为该声明类型的扩展中的组件。这种方法极大地提高了灵活性和能力,其中最重要的一点是包装过程的多个实例可以在任何时候都存在,但代价是一些冗长。
Fortran 2008 引入了另一个使用内部过程的选项,缺少的参数通过主机关联从主机过程传递到内部过程。(这种方法在以前的标准中不可用,因为不允许将内部过程作为实际过程参数传递)。通过使用过程指针,可以存在包装过程的多个实例。
附上四种不同方法的示例。请注意,在 F3 过程的任何示例中都没有声明other
和junk
实体,为了示例,可能还有一些其他遗漏(或者我认为非常糟糕的编程风格)。此外,请注意,这四种方法在代码的灵活性和健壮性(捕获程序员错误的可能性等)方面存在很大差异。
C*******************************************************************************
C FORTRAN 77
FUNCTION F1(FUNC,OTHER,JUNK)
F1=FUNC(OTHER)+JUNK
END FUNCTION F1
C
FUNCTION F2(K,G,X)
F2=K+G+X
END FUNCTION F2
C
FUNCTION F3(K,G)
COMMON /F2COM/KC,GC
KC=K
GC=G
F3=F1(F2WRAP,OTHER,JUNK)
END FUNCTION F3
C
FUNCTION F2WRAP(X)
COMMON /F2COM/KC,GC
F2WRAP=F2(KC,GC,X)
END FUNCTION F2WRAP
!*******************************************************************************
! Fortran 90/95
MODULE m1990
IMPLICIT NONE
INTEGER :: km
REAL :: gm
CONTAINS
FUNCTION F2Wrap(x)
REAL :: x
!****
! F2 unchanged from F77, though good practice would be to make
! it (and F1 and F3) module procedures.
! ensure it had an explicit interface here.
F2Wrap = F2(km,gm,x)
END FUNCTION F2Wrap
END MODULE m1990
FUNCTION F3(k,g)
USE m1990
IMPLICIT NONE
INTEGER :: k
REAL :: g, F3
!****
km = k
gm = g
! F1 unchanged from F77.
F3=F1(F2Wrap, other, junk)
END FUNCTION F3
!*******************************************************************************
! Fortran 2003
MODULE m2003
IMPLICIT NONE
TYPE Functor
CONTAINS
PROCEDURE(fun_intf), DEFERRED :: fun
END TYPE Functor
ABSTRACT INTERFACE
FUNCTION fun_intf(f,x)
IMPLICIT NONE
IMPORT :: Functor
CLASS(Functor), INTENT(IN) :: f
REAL :: x, fun_intf
END FUNCTION fun_intf
END INTERFACE
TYPE F2Functor
INTEGER :: k
REAL : g
CONTAINS
PROCEDURE :: fun => F2_wrap
END TYPE F2Functor
CONTAINS
FUNCTION F2_wrap(f,x)
CLASS(F2Functor), INTENT(IN) :: f
REAL :: F2_wrap, x
! F2 unchanged from F77
F2_wrap = F2(f%k, f%g, x)
END FUNCTION f2_wrap
! F1 modified. Now takes a polymorphic argument in-place of the
! dummy procedure - explicit interface REQUIRED.
FUNCTION F1(f, other, junk)
CLASS(Functor), INTENT(IN) :: f
REAL :: F1, other
INTEGER :: junk
F1 = f%fun(other) + junk
END FUNCTION
END MODULE m2003
! Good practice would make this a module procedure.
FUNCTION f3(k,g)
USE m2003
IMPLICIT NONE
TYPE(F2Functor) :: f
REAL F3, g
INTEGER :: k
!****
f%k = k
f%g = g
F3 = F1(f, other, junk)
END FUNCTION f3
!*******************************************************************************
! Fortran 2008 (use of procedure pointers not illustrated).
! Should be a module proc, etc...
FUNCTION F3(k,g)
REAL :: F3, g
INTEGER :: k
INTEGER :: k_host
REAL :: g_host
k_host = k
g_host = g
! F1 unchanged from F77 (though good practice is..., etc)
F3 = F1(F2Wrap, other, junk)
CONTAINS
FUNCTION F2Wrap(x)
REAL :: x, F2Wrap
! F2 unchanged from F77.
F2Wrap = F2(k_host, g_host, x)
END FUNCTION F2Wrap
END FUNCTION F3
假设我正确地解释了这一点,那么是的。
program func_test
integer :: a, b
a = 4
b = 3
print *,f3(a,b)
print *,f3(b,a)
contains
function f3(k,g)
integer :: k, g, x, f3
x = 2
f3 = f1(f2(k,g,x), 3, 13)
end function f3
function f2(k, g, x)
integer :: k, g, x, f2
f2 = k+g*x
end function f2
function f1(func, other, junk)
integer :: func, other, junk
f1 = func + other*junk
end function f1
end program func_test
除非我弄错了,否则f2(k,g,x)
在此示例中将进行评估,然后将其f1
作为整数发送。如果你想f2
被from f1
调用,那么你还必须传递参数k
,g
和x
from f3
to f1
。