0

I want to create a function composition in Fortran. The idea is if I have f(x) and g(x), I want to find f(g(x)). It is simple in syntax in python Better Function Composition in Python.

Here is a sample Fortran code:

module test10
implicit none
contains
    function f5x (x)
        real :: f5x
        real, intent (in) :: x
        f5x = 5.00*x
    end function f5x

    function f10x (x)
        real :: f10x
        real, intent (in) :: x
        f10x = 10.00*x
    end function f10x


end module test10


program call_test10
    use test10
    implicit none
    real :: val1, val2, input


    interface 
    real function fx_new (y)
        real, intent (in) :: y
    end function fx_new
    end interface


    input=1.0
    write (*,*) 'Invoking f5x'
    val1 = f5x(1.0)
    write (*,*) val1
    write (*,*) 'Invoking f10x'
    val1 = f10x(1.0)
    write (*,*) val1
    write (*,*) 'Invoking f10x(f5x)'
    procedure (fx_new), pointer :: ptr1 => f5x
    procedure (fx_new), pointer :: ptr2 => f10x
    val2 = ptr2(ptr1)
    write (*,*) val2

 end program call_test10

The statements val1 = f5x(1.0) and val1 = f10x(1.0) run by themselves. But when it comes to function composition, I don't know how to achieve that in Fortran. I want to evaluate f10x(f5x) and then want to assign value to x. Any ideas?

If I include a module file and function return type, number of arguments, and type of arguments match, can Fortran compiler decide which function to execute in the included file? Another thing I would like to know is can I get rid of the interface (by using procedure pointer or something else)? The whole idea of interface to execute external functions looks confusing to me, so please suggest a way to execute external functions without interface, if possible. I am aware of keyword external, but it was meant for much earlier versions (though it continues to work in newer standards).

As procedure pointers are in newer standards (2003, 2008, ...), I would use Fortran standard 2008.

Community
  • 1
  • 1
  • closure is not possible in fortran. – wey273824 Jul 26 '16 at 00:50
  • 1
    I don't think you can accomplish this task without resorting to both user-defined derived data types with pointer type-bound procedures and C-language style casting achieved through the procedure `c_f_pointer` in `iso_c_binding`. Anyways, function compositions violates how arguments are passed in Fortran. See: https://software.intel.com/en-us/blogs/2009/03/31/doctor-fortran-in-ive-come-here-for-an-argument – jlokimlin Jul 26 '16 at 01:31

3 Answers3

4

This is an example I have already shown here Dynamic function creation from another function (have you searched?). I think the question is not an exact duplicate, so I am reusing instead of closing. Others can review this.

module ComposeObj
  !here use modules defining your working kind as you wish

  implicit none

  private
  public Compose

  abstract interface
    !declare fce as a function of the type you wish, probably a real function of a real variable    
  end interface

  type Compose
    private
    procedure(fce),pointer,nopass :: f1 => null(),f2=>null()
  contains
    procedure,public :: call => helper
  endtype 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(work_kind) function helper(this,x)
    class(Compose),intent(in) :: this
    real(work_kind),intent(in) :: x
    helper = this%f1(this%f2(x))
  end function helper

end module ComposeObj

Basically you have to prepare the class which can do function composition in advance. You cannot just create a closure on the fly.

But you can dynamically assign function pointers to functions you want, that does not have to be done in advance.

And you than have to use it using the %call(x) method, you cannot override the () because it is not an operator in Fortran (it is in C++).

   type(Compose) :: f1_f2
   f1_f2 = Compose(f1, f2)

   val2 = f1_f2%call(x)

Locally, you can use internal functions. It has been shown numerous times here by me and by others. It is not worth to repeat everything, just a code example:

  val2 = composed_f1_f2(x)

contains

  function composed_f1_f2(x)
    real :: composed
    real, intent(in) :: x
    composed = f1(f2(x))
  end function
Community
  • 1
  • 1
1

I don't think that's possible the way you want it to.

Before I start: Even in languages that would allow this kind of thing, if you typed something like the ptr2(ptr1) as you do, the result would be a function, not a value. You wouldn't be able to store it in a REAL variable.

You could write your own function, like this:

function my_func(x)
    use test10, only: f5x, f10x
    implicit none
    real, intent(in) :: x
    real :: my_func
    my_func = f10x(f5x(x))
end function my_func
chw21
  • 7,970
  • 1
  • 16
  • 31
0

This is maybe a bit of a naive way of looking at it, but Fortran allow passing functions as an argument, so you could have:

real function f(x, g)
external g
real x
is_g_present = PRESENT(g) 

if is_g_present:
    ! Do something with g and x
else:
    ! Do f(x) normally
endif
return

This would allow you to call f as f(x) or f(x,g). It's not exactly what you are asking for, but is a nice and easy workaround for Fortran.

(Pseudocode since I don't have a machine to test I'm not writing something totally stupid right now, I would write this just as a comment but I lack the reputation at the moment, sorry)

Scarlehoff
  • 89
  • 3