fortran でサブルーチンの引数にサブルーチンを渡す

fortran のプログラムにおいてサブルーチンの引数にサブルーチン名を書いて処理の細かい部分を変更したいと思った。C言語なら

定義:void refer ( void (*proc) ( void ) ) { proc() ; }
   void hello(void){ printf("hello"); }
呼出:refer(hello);
のように書くところ。
実引数が手続である場合,その対応する仮引数は仮手続となります。仮手続は関数またはサブルーチン副プログラム中に置くことができます。(強調あらき)
http://www.xlsoft.com/jp/products/intel/cvf/docs/vf-html/lr/lr08_07_07.htm
というわけでfortranでも同じように関数やサブルーチンを引数として渡すことが出来る。
実引数としては,変数,式,または手続名を使用することができます。実引数の型,種別パラメタ,および次元数は,それに結合された仮引数と一致していなくてはなりません。

副プログラムとして引用されている仮引数は,呼び出し側ルーチンで EXTERNAL または INTRINSIC として宣言された実引数と結合されなくてはなりません。(強調あらき)
http://www.xlsoft.com/jp/products/intel/cvf/docs/vf-html/lr/lr08_07.htm
C言語の場合と同様に関数の戻り値と引数の型を明示的に書かないといけない。Cの場合、この明示的に書く作業は、関数の定義で関数の引数の中で書くが、fortranの場合は INTERFACE 文で定義する。例えばCのソースで
int refer ( double (*func)( int* ) ) { [def] }
とある部分は(引数はわざとアドレスで渡すように書いた)、fortranでは次のようになる:

INTEGER FUNCTION refer (func)
  INTERFACE
    REAL(8) FUNCTION func (a)
      INTEGER,INTENT(IN):: a
    END FUNCTION
  END INTERFACE
  [def]
END FUNCTION

fortranでは手続(関数、サブルーチンなど)の引数の並びと引数の型宣言をバラバラに書く仕様なのでこのような書き方になるのだろう。*1
注意すべき点は手続を引数にとる手続を呼び出すときに、手続が引数に代入できるように EXTERNAL 宣言をしなくてはいけないことである。つまり実際に refer に func を代入して動作させる部分のソースは次のようになる

EXTERNAL func ! 宣言部でこの行が必須
I= refer(func)
Cではこのような宣言は要らない(だから意図しないアドレスを渡してしまうこともできる)。fortranではこのEXTERNAL宣言のおかげで、関数が存在しないときにコンパイルの段階で文法エラーを返すことが出来るようになっているようだ。
サンプル・プログラム(デモ用のミニマル・コンプリート)
PROGRAM main ! main が「呼び出し側ルーチン」
EXTERNAL A,B ! 「EXTERNALとして宣言」
CALL REFER(A) ! この A, B が「手続きである実引数」
CALL REFER(B)
END PROGRAM

SUBROUTINE REFER(PROC) ! この PROC が「仮手続」
INTERFACE
SUBROUTINE PROC
END
END INTERFACE
CALL PROC
RETURN
END

SUBROUTINE A
WRITE(*,*) 'hello A()'
RETURN
END

SUBROUTINE B
WRITE(*,*) 'hello B()'
RETURN
END

[2010.2.15] 手許のg95でコンパイルしてみたら、EXTERNAL文が無くてもCALLしてあれば通るみたい
PROGRAM main ! main が「呼び出し側ルーチン」
EXTERNAL B ! 「EXTERNALとして宣言」
CALL REFER(A) ! この A, B が「手続きである実引数」
CALL REFER(B)
CALL A ! A を呼び出していたら EXTERNAL は要らないらしい
END PROGRAM

*1:蛇足だが、C言語の場合、関数 func() を定義すると、関数名 func で関数のインスタンスの先頭アドレス(?)を指し、関数名+括弧 func() で関数の戻り値を示す。Cは「メモリ上に書かれたデータ」と「データのあるメモリのアドレス」を丁寧に書き分けられるように出来ている。fortranは変数名を書いたときに、文ならば「データ」、引数なら「アドレス」なのだが、どちらも同じ表記なので動作をイメージするときに分かりにくいように思われる。