Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
620 views
in Technique[技术] by (71.8m points)

fortran - Pointers in pure functions

In order to traverse a linked list in Fortran, I use a pointer to the current element that is moved to the next one inside a loop. Trying to apply this inside a pure function that operates on said linked list results in an error.

Example:

module list
  implicit none

  ! Node
  type n_list
    integer               :: val
    type(n_list),pointer  :: next => NULL()
  end type

  ! Linked list
  type t_list
    type(n_list),pointer  :: head
  end type

contains

  pure function in_list( list, val ) result(res)
    implicit none
    class(t_list),intent(in)  :: list
    integer,intent(in)        :: val
    logical                   :: res
    type(n_list),pointer      :: cur

    res = .true.
    ! Traverse the list
    cur => list%head
    do while ( associated(cur) )
      if ( cur%val == val ) return 
      cur => cur%next
    enddo

    ! Not found
    res = .false.
  end function
end module

Results in

    cur => list%head
         1
Error: Bad target in pointer assignment in PURE procedure at (1)

I am aware of the rationale behind the error/warning, and that it is difficult to ensure that the arguments of the function are not changed when using pointers (Fortran 2008, ch. 12.7 "Pure procedures", esp. C1283). In this case, though, list is never changed.

Is it possible to tell the compiler (ifort and gfortran) that intent(in) is not violated?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I have found a solution using recursive functions that is at least Standard conforming. It is neither elegant nor fast, and is limited be the stack depth, but it is working. I'll post it as an answer, although I hope some-one has a better solution...

module list
  implicit none

  ! Node
  type n_list
    integer               :: val
    type(n_list),pointer  :: next => NULL()
  end type

  ! Linked list
  type t_list
    type(n_list),pointer  :: head
  end type

contains

  pure function in_list( list, val ) result(res)
    implicit none
    class(t_list),intent(in)  :: list
    integer,intent(in)        :: val
    logical                   :: res

    if (  associated(list%head) ) then
      res = in_list_node( list%head, val ) 
    else
      res = .false.
    endif
  end function

  recursive pure function in_list_node( node, val ) result(res)
    implicit none
    class(n_list),intent(in)  :: node
    integer,intent(in)        :: val
    logical                   :: res

    if ( node%val == val ) then
      res = .true.
    elseif ( associated(node%next) ) then
      ! Recurse
      res = in_list_node( node%next, val ) 
    else
      res = .false.
    endif
  end function
end module

program test
  use list
  implicit none
  integer,parameter     :: MAXELEM = 100000
  integer               :: i
  type(t_list)          :: lst
  type(n_list),pointer  :: cur

  ! Fill list
  lst%head => NULL()
  allocate( lst%head )
  lst%head%val = 1

  cur => lst%head
  do i=2,MAXELEM
    allocate( cur%next )
    cur%next%val = i
    cur => cur%next
  enddo !i

  print *,'is MAXELEM/2 in list? ', in_list( lst, MAXELEM/2 )
  print *,'is MAXELEM+1 in list? ', in_list( lst, MAXELEM+1 )
end program

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...