Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic function creation from another function

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.

like image 632
Eric Langlois Avatar asked Mar 13 '12 21:03

Eric Langlois


2 Answers

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
like image 153
Vladimir F Героям слава Avatar answered Oct 31 '22 10:10

Vladimir F Героям слава


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.

like image 33
M. S. B. Avatar answered Oct 31 '22 12:10

M. S. B.