Fortran - 从子程序返回一个匿名函数 [英] Fortran - Return an anonymous function from subroutine
问题描述
我试图推广一个子程序的函数调用。所以我的想法是这样的
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>解决方案
后面的大规模推测有希望成为避免匿名函数需求的有用方法。 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屋!