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 .
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