截断Fortran 95函数中的变量数

时间:2013-09-25 21:49:05

标签: fortran

假设我想通过f1(f2(k, g, x), other, junk)将函数传递给另一个函数(f1定义为f1(func, other, junk),它涉及func(other)等表达式。)进一步假设两者都有这些函数包含在第三个函数f3(k, g)中。通过使用f3(k, g)k的某些值调用gf2不再是三个变量的函数,是吗?它只是x的函数,因为kg现在是常量。所以我想知道的是,在我定义你的时候,是否有某种方式说“看,f2,你不知道kg是什么,但现在你告诉我f3他们是什么,所以你可以认为自己是x的函数,所以当我把你带到f1时,它只能看到并使用一个函数一个变量。“

2 个答案:

答案 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调用,那么您还必须传递参数f1k和{{1从gx

答案 1 :(得分:0)

我认为你正在寻找的东西有时被称为“函子/函数对象”或lambda表达式 - 能够用一些参数包装一个过程,以便可以用更少的参数调用它(缺少的)参数通过其他方式指定)。

在Fortran 77中,这通常通过在公共块中通过幕后传递“缺失”参数来近似。通过让你使用模块变量,Fortran 90/95的变化很大。这两种方法都有缺点,即一次只能存在一个包装过程的单个实例,尽管由于其他原因,在普通块上使用模块是一个非常优越的选择。

Fortran 2003引入了其他选项 - 使用派生类型和类型扩展。这需要更改f1的代码 - 而不是使用伪过程参数,该函数采用多态参数,其声明的类型具有绑定,该绑定具有类似于f1的前一个参数但具有传递对象的接口。缺少的参数然后成为该声明类型的扩展中的组件。这种方法带来了灵活性和能力的巨大增长,其中最重要的是,包装过程的多个实例可以在任何时候存在,代价是一些冗长。

Fortran 2008引入了另一个使用内部过程的选项,缺少的参数通过主机关联从主机过程传递到内部过程。 (此方法在以前的标准中不可用,因为不允许将内部过程作为实际过程参数传递)。通过使用过程指针,可以存在包装过程的多个实例。

附加四种不同方法的示例。请注意,在F3过程的任何示例中都没有声明otherjunk实体,并且可能存在一些其他遗漏(或者我认为编程风格很差)这个例子。此外,请注意,这四种方法在代码的灵活性和健壮性方面差异很大(程序员错误被捕获的可能性等)。

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