我的最终目标是在Fortran中拥有一个通用的映射函数,即,该函数接受任意类型A的数组和类型A-> B的函数,将此函数应用于给定数组的所有元素,并返回类型B的数组。我无法使用数组来实现,所以我决定仅从单个元素开始,但即使这样也不起作用。
这是我的尝试:
program main
integer :: elem_int
elem_int = 1
elem_int = to_int(apply_func(elem_int, add_one_int))
print *, elem_int
contains
! don't know any other way to cast class(*) to int
function to_int(unbound) result(res)
class(*), intent(in) :: unbound
integer :: res
select type (unbound)
type is (integer)
res = unbound
end select
end function
function apply_func(elem, func) result(new_elem)
class(*) :: elem
class(*) :: func
class(*), allocatable :: new_elem
! not sure if this allocation is needed
allocate(new_elem, source = elem)
new_elem = func(elem)
end function
function add_one_int(num) result(res)
integer :: num
integer :: res
res = num + 1
end function
end program
此代码可编译,但由于在线错误而崩溃
new_elem = func(elem)
我认为也许它以为func是一个数组并尝试为其建立索引,所以我尝试定义如下的抽象接口:
abstract interface
function any_func(x)
class(*) :: x
class(*), allocatable :: any_func
end function
end interface
并将func
的声明更改为procedure(any_func)
,但是随后我的编译器(ifort 18.0.1)产生以下错误:
error #7069: The characteristics of the associated actual function result differ from the characteristics of the dummy function result. [ADD_ONE_INT]
我想要一个接口,以便任何1-arg函数都符合该接口,但是,显然,这不是声明它的正确方法。有什么想法在工作时如何做到这一点吗?预先感谢。
答案 0 :(得分:2)
经过一番挖掘,我了解到将一个函数标记为elemental
时,它可以应用于数组,本质上提供了我一直在寻找的相同功能。这是int->real
类型的函数的示例
program main
integer :: int_arr(3)
real :: real_arr(3)
int_arr = [1, 2, 3]
real_arr = my_sqrt(int_arr)
print *, real_arr
contains
elemental function my_sqrt(arg) result(res)
integer, intent(in) :: arg
real :: res
res = sqrt(real(arg))
end function
end program
答案 1 :(得分:2)
即将到来的标准Fortran 2018包括新的构造select_rank
,它将为编码与等级无关的过程带来更大的灵活性,而不受elemental
过程的约束。直到今天(2018年底),该标准才刚刚由ISO正式发布,因此可能需要一段时间才能被供应商实施。
仅出于琐事考虑,gfortran 8.2.0
中存在一个错误,该错误允许使用map
伪参数在Fortran中编写一种assumed-rank
子例程,而没有{ {1}}(或每个等级的特定例程)。
重要提示::我不建议将此代码段用于生产代码。我决定发布它只是为了感谢可能会担任此职位的Fortran同事,希望它可以提供对语言的更好理解并启发一些想法。 @DartLenin的self answer是在Fortran中执行此操作的正确方法。
select_rank
注意:
module maps
implicit none
abstract interface
integer function unary_int(x)
integer :: x
end function
! different interfaces would be needed for other arities an types
end interface
interface map
procedure :: map_unary_int ! + overloads for other implementations
end interface
contains
subroutine map_unary_int(f, x)
procedure(unary_int) :: f
integer :: x(..)
call apply_flatten(x) ! <- there is the bug: assumed-rank variable shouldn't
! be allowed as actual argument to assumed-size
contains
subroutine apply_flatten(x_)
integer :: x_(size(x)), i
x_(1:size(x)) = [(f(x_(i)), i=1, size(x))]
end
end
end
program main
use :: maps
implicit none
integer :: int_scl = 0, int_1(1) = 1, int_2x2(2, 2) = 2
call map(add1, int_scl)
print *, int_scl, "sh:", shape(int_scl) ! prints: 1 sh:
call map(add1, int_1)
print *, int_1, "sh:", shape(int_1) ! prints: 2 sh: 1
call map(add1, int_2x2)
print *, int_2x2, "sh:", shape(int_2x2) ! prints: 3 3 3 3 sh: 2 2
contains
integer function add1(num)
integer :: num
add1 = num + 1
end function
end program
约束和大量重写。