Advertisement
chemoelectric

looping with class(*)? Easy as a tail recursion

Nov 20th, 2021
2,856
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. module cons_pairs
  2.   use iso_fortran_env, only : error_unit
  3.  
  4.   implicit none
  5.  
  6.   type cons_nil
  7.   end type cons_nil
  8.  
  9.   type cons_pair
  10.      class(*), allocatable :: car
  11.      class(*), allocatable :: cdr
  12.   end type cons_pair
  13.  
  14.   contains
  15.  
  16.     function nil () result (lst)
  17.       class(cons_nil), allocatable :: lst
  18.       allocate (lst)
  19.     end function nil
  20.  
  21.     function is_nil (object) result (truth)
  22.       class(*) :: object
  23.       logical :: truth
  24.       select type (object)
  25.       class is (cons_nil)
  26.          truth = .true.
  27.       class default
  28.          truth = .false.
  29.       end select
  30.     end function is_nil
  31.  
  32.     function is_pair (object) result (truth)
  33.       class(*) :: object
  34.       logical :: truth
  35.       select type (object)
  36.       class is (cons_pair)
  37.          truth = .true.
  38.       class default
  39.          truth = .false.
  40.       end select
  41.     end function is_pair
  42.  
  43.     function cons (car, cdr) result (pair)
  44.       class(*), intent(in) :: car
  45.       class(*), intent(in) :: cdr
  46.       class(cons_pair), allocatable :: pair
  47.       allocate (pair)
  48.       pair%car = car
  49.       pair%cdr = cdr
  50.     end function cons
  51.  
  52.     function car (pair) result (element)
  53.       class(*), intent(in) :: pair
  54.       class(*), allocatable :: element
  55.       select type (pair)
  56.       class is (cons_pair)
  57.          element = pair%car
  58.       class default
  59.          write (error_unit, '("Error: ", a)') &
  60.               "car(p) where p is not a cons_pair"
  61.          call abort
  62.       end select
  63.     end function car
  64.  
  65.     function cdr (pair) result (element)
  66.       class(*), intent(in) :: pair
  67.       class(*), allocatable :: element
  68.       select type (pair)
  69.       class is (cons_pair)
  70.          element = pair%cdr
  71.       class default
  72.          write (error_unit, '("Error: ", a)') &
  73.               "cdr(p) where p is not a cons_pair"
  74.          call abort
  75.       end select
  76.     end function cdr
  77.  
  78.     function list_length (lst) result (length)
  79.       ! FIXME: Does not check for circular list.
  80.       class(*), value :: lst
  81.       integer :: length
  82.       length = loop (lst, 0)
  83.     contains
  84.       recursive function loop (lst, len) result (length)
  85.         class(*), value :: lst
  86.         integer, value :: len
  87.         integer :: length
  88.         select type (lst)
  89.         class is (cons_nil)
  90.            length = len
  91.         class is (cons_pair)
  92.            length = loop (lst%cdr, len + 1)
  93.         class default
  94.            write (error_unit, '("Error: ", a)') &
  95.                 "list_length (lst) where lst is not a proper list"
  96.            call abort
  97.         end select
  98.       end function loop
  99.     end function list_length
  100.  
  101. end module cons_pairs
  102.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement