I have a Fortran 90 subroutine which takes a function as an argument, and I would like to pass a modified version of that function into another subroutine. I want the program to look something like this:
subroutine foo(f, ...)
    real                 :: pt(2), dir(2)
    interface
    function f(x) result(y)
        real, intent(in) :: x(2)
        real             :: y
    end function f
    end interface
    pt = ...
    dir = ...
!! Somehow create g(x) = f(pt + x*dir)
    call bar(g)
end subroutine foo
subroutine bar(g)
    interface
    function g(x) result(y)
        real, intent(in) :: x
        real             :: y
    end function g
    end interface
!! Do stuff with g
end subroutine bar
I've managed to do something similar when 'g' only needs to use normal variables, not a function. In that case I made it a global function, using global variables, and assigned to those global variables in 'foo'. However, I can't find a way to turn 'f' global, or assign it to a global function.
Anybody have any ideas how to do this? The solution can be as hacky as you want.
This is not so easy. In some languages you can pass pointers to nested functions in a so called closure. This is not possible in Fortran (or C and similar languages), because the data are destroyed with the stack of the higher function. I would suggest you to try function objects, i.e. a class with a function pointer (or more) and data needed for the function. In this way you can even do function composition and similar functional stuff.
More on the concept http://en.wikipedia.org/wiki/Function_object
Below is a sample for a function object for composition of two single argument functions:
module ComposeObj
  use Parameters, only: rp
  use AritmFunctions, only: fce
  implicit none
  private
  public Compose
  type Compose
    private
    procedure(fce),pointer,nopass :: f1 => null(),f2=>null()
  contains
    procedure,public :: call => helper
  end type Compose
  interface Compose
    procedure NewCompose
  end interface
 contains
  function NewCompose(f,g)
    procedure(fce) :: f,g
    type(Compose) :: NewCompose
    NewCompose%f1 => f
    NewCompose%f2 => g
  end function NewCompose
  pure real(rp) function helper(this,x)
    class(Compose),intent(in) :: this
    real(rp),intent(in) :: x
    helper = this%f1(this%f2(x))
  end function helper
end module ComposeObj
                        You could do a lot with procedure pointers, constructing a function that is a combination of other functions. See Function pointer arrays in Fortran for a code example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With