fortran66のブログ

fortran について書きます。

Fortranで似非リスト処理

Fortran2003では、Array操作がさらに柔軟になっています。ALLOCATABLEな配列を返り値とする関数と、ALLOCATABLE配列の自動再割付が、色々と危険なんですが、便利です。

これらの新機能により、APPENDやCONSのような配列長の変わる操作が簡単に実現できます。

MAPにあたるものは、Fortran95で導入されたELEMENTALな関数で実現できます。(INTRINSICな関数はFortran90からELEMENTALになっていますが)

FILTERにあたるものは、PACK関数によって実現できます。(効率は低そうな気がしますが)

簡単な内包式に当たるものは、配列生成子(array constructor)によって実現できます。

■実行結果

■ソース・コード

gdgdで統一感がないんですが・・

MODULE m_test
 IMPLICIT NONE
 CONTAINS

 FUNCTION iseq(n0, n1, n2)
   INTEGER, ALLOCATABLE :: iseq(:)
   INTEGER, INTENT(IN) :: n0, n1
   INTEGER, INTENT(IN), OPTIONAL :: n2
   INTEGER :: i, istep
   IF ( PRESENT(n2) ) THEN
    istep = n2
   ELSE
    istep = 1
   END IF
   iseq = [(i, i = n0, n1, istep)]
   RETURN
 END FUNCTION iseq

 ELEMENTAL INTEGER FUNCTION parity(n)
   INTEGER, INTENT(IN) :: n
   parity = MOD(n, 2)
   RETURN
 END FUNCTION parity

END MODULE m_test
!=====================================
PROGRAM test
 USE m_test
 IMPLICIT NONE
 INTEGER, ALLOCATABLE :: a(:), b(:), c(:)
 INTEGER :: i

 a = [(i,  i = -5, 10)]
 b = PACK(a, a > 4)
 WRITE(*, '(a, 20i3:)', ADVANCE = 'NO') ' a = -5..10         [', a
 WRITE(*, '(a)') ' ]'
 WRITE(*, '(a, 20l3:)', ADVANCE = 'NO') ' a > 4              [', a > 4
 WRITE(*, '(a)') ' ]'
 
 PRINT *
 WRITE(*, '(a)') ' filter '
 WRITE(*, '(a, 20i3:)', ADVANCE = 'NO') ' b = PACK(a, a > 4) [', b
 WRITE(*, '(a)') ' ]'
 PRINT *

 c = [b, a] ! flatten
 b = [1,  b]  ! cons
 b = [b, [97, 99]] ! append
 WRITE(*, '(a, (25i3:))', ADVANCE = 'NO') ' b ++ a [', c
 WRITE(*, '(a)') ' ]'
 PRINT *
 WRITE(*, '(a, 20i3:)', ADVANCE = 'NO') ' b = CONS(1, b) ++ [97,99]  [', b
 WRITE(*, '(a)') ' ]'
 WRITE(*, '(a, 20i3:)', ADVANCE = 'NO') '     MAP  parity b          [', parity(b)  ! MAP
 WRITE(*, '(a)') ' ]'
 PRINT *
 WRITE(*, '(a, 20i3:)', ADVANCE = 'YES') ' CAR b   ', b(1)    ! CAR
 WRITE(*, '(a, 20i3:)', ADVANCE = 'NO' ) ' CDR b  [', b(2:)   ! CDR
 WRITE(*, '(a)') ' ]'

 STOP
END PROGRAM test