Přeskočit na obsah

Funkcionální programování v jazyce Fortran

Funkcionální programování (FP) je další programátorské paradima. Fortran obsahuje prvky vycházející z tohoto paradigmatu např. pure funkce, ale nejde o jazyk čistě funkcionální. Funkcionální programování se dost liší od předchozích představ. Na program se můžeme dívat jako na vyhodnocování funkcí. Program chápeme jako funkci, kterou lze rozložit na pod-funkce. Při programování neřešíme jak se to má udělat, ale co se má udělat.

FP operuje s funkcemi vyšších řádů. To jsou funkce, které mohou jako argunemt příjmout jinou funkci nebo vrátit funkci jako výsledek.

Když píšeme kód ve stylu FP používáme pure funkce. To je klíčový prvek! Pure funkce znamená, že výsledek funkce je závislí jen na vstupních argumentech a NE globálních proměnných. To v důsledku vede v velmi bezpečné paralelizaci. Proto do concurrent operuje jen s pure funkcemi.

V FP nepužívá cykly, ale nahrazuje je rekurzí. To znamená, že opakování zajistíme pomocí funkce která volá samu sebe. Ve fortranu se v praxi takto asi vždy chovat nebudem. Ve většině případů se rekurzi resp. cyklu vyhneme použitím některé funkce vyššího řádu.

Tato část je opět převážně pro ty, kteří již mají s FP nějaké zkušenosti.

Zajímavý se zdá modul https://github.com/wavebitscientific/functional-fortran. Obsahuje základní výbavu funkcí vyššího řádu, které jsou běžné v FP.

Jak na funkce vyššího řádu

V příkladu je ukázka realizace dvou funkcí vyššího řádu. Funkce test dokáže vráti funkci jako výsledek. A funkce test2 umí příjmout funkci jako argument.

    module fce
    implicit none
      
      private
      
      public :: i_f1, test, test2
    
      abstract interface
        real pure function i_f1(x)
          real,intent(in) :: x
        end function
      end interface
    
    contains
    !-----------------------------------------------------------------------
    pure real function test2(x,f)
      real, intent(in) ::  x
      procedure(i_f1) :: f
      
      test2 = f(x) 
        
    end function
    !-----------------------------------------------------------------------
    pure function test(x)
      integer, intent(in) ::  x
      procedure(i_f1),pointer :: test
      
      if(x==1) then
        test => f
      else
        test => g
      endif
        
    end function
    !-----------------------------------------------------------------------
    pure real function f(x)
      real,intent(in) :: x
      f = x**3
    end function
    !-----------------------------------------------------------------------
    pure real function g(x)
      real,intent(in) :: x
      g=x**(1./2.)
    end function
    !-----------------------------------------------------------------------
    end module
    !=======================================================================
    program main
    use fce
    implicit none
      
      procedure(i_f1),pointer :: p => null()
      
      p = test(1)
      
      write(*,*) p(2.0)
      write(*,*) test2(2., p)
      write(*,*) test2(2., test(1))
      write(*,*) test2(2., test(2))
    
    end program

Funkce map

Funkce map je běžnou funkcí vyššího řádu v FP. Tato funkce má dva argumenty - pole hodnot a funkci, kterou aplikujeme na každý prvek pole zvlášť. To znamená map(f, \[x_1,x_2,...\]) = \[f(x_1), f(x_2),...\].

    module fce
    implicit none
      
      private
      
      public :: map, f
    
      abstract interface
        real pure function fr_r1(x)
          real,intent(in) :: x
        end function
      end interface
    
    contains
    !---------------------------------------
    pure function map(f, x)
      real, intent(in) ::  x(:)
      procedure(fr_r1) :: f
      real :: map(lbound(x,dim=1):ubound(x,dim=1))
      integer :: i
      
      do concurrent(i=lbound(x,dim=1):ubound(x,dim=1))
        map(i) = f(x(i))
      enddo
        
    end function
    !---------------------------------------
    real pure function f(x)
      real, intent(in) ::  x
      
      f = x * x
        
    end function
    !---------------------------------------
    end module
    !=======================================
    program main
    use fce
    implicit none
      
      integer :: i
      real,allocatable :: a(:)
      
      a = [(i*1., i=1,10)]
      
      write(*,*) a
      write(*,*) map(f,a)
      
    end program
    					

funkce filter

Funkce filter je další klasickou přetíženou funkcí. Vstupem je funkce a pole. Funkce vrátí pro každou hodnotu pole logickou hodnotu. Výsledkem je pole hodnot pro které platí, že f(x(i))=.true.f(x(i)) = .true..

    module fce
    implicit none
      
      private
      
      public :: filter, f
    
      abstract interface
        logical pure function fl_r1(x)
          real,intent(in) :: x
        end function
      end interface
    
    contains
    !---------------------------------------
    pure function filter(f, x)
      real, intent(in) ::  x(:)
      procedure(fl_r1) :: f
      real,allocatable :: filter(:)
      logical :: f_x(lbound(x,dim=1):ubound(x,dim=1))
      integer :: i
      
      do concurrent(i=lbound(x,dim=1):ubound(x,dim=1))
        f_x(i) = f(x(i))
      enddo
      filter = pack(x,f_x)
    end function
    !---------------------------------------
    logical pure function f(x)
      real, intent(in) ::  x
      
      f = .false.
      if(mod(x**2,2.)==0.0) f=.true.
        
    end function
    !---------------------------------------
    end module
    !=======================================
    program main
    use fce
    implicit none
      
      integer :: i
      real,allocatable :: a(:)
      
      a = [(i*1., i=1,10)]
      
      write(*,*) a
      write(*,*) filter(f,a)
    
    end program