Fortran - 从子程序返回一个匿名函数 [英] Fortran - Return an anonymous function from subroutine

查看:162
本文介绍了Fortran - 从子程序返回一个匿名函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图推广一个子程序的函数调用。所以我的想法是这样的

  if(case1)then 
call MainSubroutine1(myFun)
elseif (case2)
调用MainSubroutine2(myFun)
如果

do i = 1,4
data = myFun(i)
end do

我意识到这有点模糊,但我不确定这是否可能。



谢谢,

John






edit 1/31/14 7:57 AM




我很抱歉我用这种模糊的方式。我正在考虑类似于@haraldki的做法,但我希望能够在MainSubroutine1和MainSubroutine2中定义一个匿名函数,并将该定义传递给主代码。



这是因为myFun依赖于不同的拉伸分布(高斯和费米 - 狄拉克),我不想有一个函数只用一个常量抛出它来调用函数。

<





div class =h2_lin>解决方案

你的问题的答案只是:不,你不能返回一个匿名函数。这是因为,正如@VladimirF在评论中所说,Fortran中没有匿名函数。正如评论所说,尽管过程指针是非常流行的。



后面的大规模推测有希望成为避免匿名函数需求的有用方法。 b
$ b

我推断你想做类似于

 子例程MainSubroutine1(fptr)
程序(func),指针,意图(out):: fptr
!计算你的匿名函数的参数化
fptr => anon_parameterized

包含
实函数anon_parameterized(i)
整数,意图(in):: i
!使用参数化
anon_parameterized = ...
结束函数
结束子例程

并且你不想这样做

$子程序mainSubroutine1(fptr)
程序(func),指针,意图(out):: fptr
fptr =>高斯
结束子程序

实函数高斯(i)
整数,意图(in):: i
!计算参数化
Gaussian = Gaussian_Parameterized(i,...)

包含
函数Gaussian_Parameterized(i,...)
整数,意图(in):: i
!...其他意图(in)参数
结束函数
结束子程序

请注意,这些不是内部的,因为传递指向其他内部的东西的指针并没有很好地实现(作为F2008功能),而且很棘手。如果我的推论是正确的,那么有可能使用模块变量来存储参数化,再次允许最终的参数化调用不是内部的 MainSubroutine1



但是,您可能想要避免模块变量,在这种情况下,您可能会考虑传递参数化函数以及函数调用:

  procedure(func),pointer :: myFun => null()

if(case1)然后
调用MainSubroutine1(myFun)
else if(case2)
调用MainSubroutine2(myFun)
end if
if(.not.associated(myFun))STOP:(

data = myFun(1,par1,par2)

啊,但是您不确定非参数化函数 myFun 需要什么参数,所以您的接口全部坏掉了,不是吗?

然后导致多态。

  module dists 

type,abstract :: par_type
end type par_type

type,extends(par_type):: par_gaussian
real :: mu = 5.2,sigma = 1.2
end type par_gaussian

type,extends(par_type):: par_fermi_dirac
real :: eps = 11.1,mu = 4.5
结束类型par_fermi_dirac

抽象接口
实函数func(i,pars)
导入par_type
整数,意图(in):: i
class (par_type),intent(in):: pars
end函数func
结束接口

包含

实函数高斯(i,pars)
整数,意图(in):: i
类(par_type),intent(in):: pars

选择类型(语法)
类是(par_gaussian)
print *,Gaussian,pars%mu, pars%sigma
gaussian = pars%mu + pars%sigma
end select
结束函数高斯

实函数fermi_dirac(i,pars)
整数,intent(in):: i
class(par_type),intent(in):: pars

选择类型(语法)
类是(par_fermi_dirac)
打印*,Fermi-Dirac,文件夹%eps,文件夹%mu
fermi_dirac =文件夹%eps +文件夹%mu
结束选择
结束函数fermi_dirac

子程序sub1(fptr,pars)
过程(func),指针,意图(out):: fptr $ b $ class(par_type),intent(out),allocatable :: pars

fptr => gaussian
allocate(par_gaussian :: pars)

结束子程序sub1

子程序sub2(fptr,pars)
过程(func),指针,意图(out):: fptr
class(par_type),intent(out),allocatable :: pars

fptr => fermi_dirac
allocate(par_fermi_dirac :: pars)

结束子程序sub2

结束模块结束符

程序编程

use dists
implicit none

class(par_type),allocatable :: pars
procedure(func),pointer :: myfun

call sub1 (myfun,pars)
print *,myfun(i,pars)

调用sub2(myfun,pars)
print *,myfun(i,pars)

end program prog

虽然这是所有的猜测。


I am trying to generalize a function call from a subroutine. So my idea is something like this

if (case1) then
   call MainSubroutine1(myFun)
elseif (case2)
   call MainSubroutine2(myFun)
end if

do i = 1,4
   data = myFun(i)
end do

I realize this is kind of vague but I am not sure if this is possible.

Thank you,

John


edit 1/31/14 7:57 AM


I am sorry for the vague way I phrased this. I was thinking something similar to what @haraldki did but I was hoping that I could define an anonymous function within MainSubroutine1 and MainSubroutine2 and transfer that definition out to the main code.

This is because myFun depends on different stretched distribution (Gaussian and Fermi-Dirac) and I don't want to have a function that only calls a function with a constant thrown it.

Is this possible?

Thank you again.

John

解决方案

The answer to you question simply is: no, you can't return an anonymous function. This is because, as @VladimirF says in the comments, there are no anonymous functions in Fortran. As the comments say, though, procedure pointers are quite passable.

Massive speculation follows which is hopefully useful as a way of avoiding the anonymous function requirement.

I infer that you would like to do something like

subroutine MainSubroutine1(fptr)
  procedure(func), pointer, intent(out) :: fptr
  ! Calculate parameterization for your "anonymous" function
  fptr => anon_parameterized

 contains
   real function anon_parameterized(i)
     integer, intent(in) :: i
     ! Use the parameterization
     anon_parameterized = ...
   end function
end subroutine

and you don't want to do

subroutine MainSubroutine1(fptr)
  procedure(func), pointer, intent(out) :: fptr
  fptr => Gaussian
end subroutine

real function Gaussian(i)
  integer, intent(in) :: i
  ! Calculate parameterization
  Gaussian = Gaussian_parameterized(i, ...)

 contains
   function Gaussian_parameterized(i, ...)
     integer, intent(in) :: i
     !... other intent(in) parameters
   end function
end subroutine

Note that these aren't internal, as passing pointers to things internal elsewhere is not well implemented (as an F2008 feature) yet, and is tricky. Passing a pointer to an internal procedure to get host association scares me.

If my inference is correct, then there is the possibility of using module variables to store the parameterization, again allowing the final "parameterized" call to be not internal to MainSubroutine1.

However, you may want to avoid module variables in which case you may consider passing passing the parameterization along with the function call:

procedure(func), pointer :: myFun => null()

if (case1) then
  call MainSubroutine1(myFun)
else if (case2)
  call MainSubroutine2(myFun)
end if
if (.not.associated(myFun)) STOP ":("

data = myFun(1, par1, par2)

Ah, but you don't know for certain what parameters the non-parameterized function myFun requires, so your interface is all broken. Isn't it?

Which then leads to polymorphism.

module dists

  type, abstract :: par_type
  end type par_type

  type, extends(par_type) :: par_gaussian
     real :: mu=5.2, sigma=1.2
  end type par_gaussian

  type, extends(par_type) :: par_fermi_dirac
     real :: eps=11.1, mu=4.5
  end type par_fermi_dirac

  abstract interface
     real function func(i, pars)
       import par_type
       integer, intent(in) :: i
       class(par_type), intent(in) :: pars
     end function func
  end interface

contains

  real function gaussian(i, pars)
    integer, intent(in) :: i
    class(par_type), intent(in) :: pars

    select type (pars)
    class is (par_gaussian)
       print*, "Gaussian", pars%mu, pars%sigma
       gaussian = pars%mu+pars%sigma
    end select
  end function gaussian

  real function fermi_dirac(i, pars)
    integer, intent(in) :: i
    class(par_type), intent(in) :: pars

    select type (pars)
    class is (par_fermi_dirac)
       print*, "Fermi-Dirac", pars%eps, pars%mu
       fermi_dirac = pars%eps+pars%mu
    end select
  end function fermi_dirac

  subroutine sub1(fptr, pars)
    procedure(func), pointer, intent(out) :: fptr
    class(par_type), intent(out), allocatable :: pars

    fptr => gaussian
    allocate(par_gaussian :: pars)

  end subroutine sub1

  subroutine sub2(fptr, pars)
    procedure(func), pointer, intent(out) :: fptr
    class(par_type), intent(out), allocatable :: pars

    fptr => fermi_dirac
    allocate(par_fermi_dirac :: pars)

  end subroutine sub2

end module dists

program prog

  use dists
  implicit none

  class(par_type), allocatable :: pars
  procedure(func), pointer :: myfun

  call sub1(myfun, pars)
  print*, myfun(i, pars)

  call sub2(myfun, pars)
  print*, myfun(i, pars)

end program prog

That's all speculation, though.

这篇关于Fortran - 从子程序返回一个匿名函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆