假设我想通过f1(f2(k, g, x), other, junk)
将函数传递给另一个函数(f1
定义为f1(func, other, junk)
,它涉及func(other)
等表达式。)进一步假设两者都有这些函数包含在第三个函数f3(k, g)
中。通过使用f3(k, g)
和k
的某些值调用g
,f2
不再是三个变量的函数,是吗?它只是x
的函数,因为k
和g
现在是常量。所以我想知道的是,在我定义你的时候,是否有某种方式说“看,f2
,你不知道k
和g
是什么,但现在你告诉我f3
他们是什么,所以你可以认为自己是x
的函数,所以当我把你带到f1
时,它只能看到并使用一个函数一个变量。“
答案 0 :(得分:0)
假设我正确地解释了这一点,那么是的。
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
。如果您希望{/ 1>}从 f2
调用,那么您还必须传递参数f1
,k
和{{1从g
到x
。
答案 1 :(得分:0)
我认为你正在寻找的东西有时被称为“函子/函数对象”或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