関数を別の関数にf1(f2(k, g, x), other, junk)
(f1
として定義されf1(func, other, junk)
、 のような式を含むfunc(other)
) で渡したいとします。さらに、これらの関数の両方が 3 番目の関数に含まれているとしますf3(k, g)
。f3(k, g)
と のいくつかの値でk
呼び出すことによって、実際にはもはや 3 つの変数の関数g
でf2
はないでしょうか? x
それはそれ以来の関数でk
あり、g
現在は定数です。だから私が知りたいのは、どういうわけか言い方があるかどうかというf2
ことです。の関数として、私があなたをに渡すときk
g
f3
x
f1
、変数が 1 つだけの関数を見て使用します。」
2 に答える
あなたが探していると思うのは、「ファンクター/関数オブジェクト」またはラムダ式と呼ばれることがあります-いくつかの引数を持つプロシージャを、より少ない引数で呼び出すことができる方法でラップする機能(不足している引数が指定されています)他の手段で)。
Fortran 77 では、これは通常、「不足している」引数を共通ブロックの舞台裏で渡すことによって概算されていました。Fortran 90/95 では、モジュール変数を使用できるようにすることで、これを変更しました。これらのアプローチには両方とも、一度に存在できるラップされたプロシージャのインスタンスが 1 つだけであるという欠点がありますが、共通ブロックに対するモジュールの使用は、他の理由から非常に優れたオプションです。
Fortran 2003 では、派生型と型拡張を使用する他のオプションが導入されています。これには、f1 のコードを変更する必要があります。仮の手続き引数を持つ代わりに、関数は多態的な引数を取ります。その宣言された型には、f1 の前の引数と同様のインターフェイスを持つが渡されたオブジェクトを持つバインディングがあります。不足している引数は、その宣言された型の拡張機能のコンポーネントになります。このアプローチにより、柔軟性と機能が大幅に向上します。特に、ラップされたプロシージャの複数のインスタンスを一度に存在させることができますが、多少の冗長性が犠牲になります。
Fortran 2008 では、内部プロシージャを使用する別のオプションが導入されています。欠落している引数は、ホスト プロシージャから内部プロシージャへのホスト関連付けを介して渡されます。(内部プロシージャーを実際のプロシージャー引数として渡すことが許可されていなかったため、このアプローチは以前の標準では使用できませんでした)。プロシージャー・ポインターを使用して、ラップされたプロシージャーの複数のインスタンスを存続させることができます。
添付の 4 つの異なるアプローチの例。other
F3 プロシージャのどの例でもandエンティティが宣言されていないことに注意してください。junk
また、例のためにいくつかの他の省略 (または非常に貧弱なプログラミング スタイルと見なされるもの) がある可能性があります。さらに、4 つのアプローチは、コードの柔軟性と堅牢性 (プログラマーのエラーがキャッチされる可能性など) の点で大きく異なることに注意してください。
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