Range Over Iterators in Ada
On this page
The original code example demonstrates the functionality of iterators and generic types in the context of managing a list structure. Since the target language is Ada, we’ll adapt these concepts to idiomatic Ada style.
Our example will use arrays for basic collection handling and demonstrate an iterative procedure to mimic the iterator pattern.
Here’s the translation to Ada, along with the necessary explanations in Markdown format suitable for Hugo:
Starting with Ada, we can define a list and push elements into it. Ada provides powerful features to manage collections and support for iteration over these collections.
First, let’s define a generic list type.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Indefinite_Holders;
package Generic_Linked_List is
type Element_Type is private;
package Element_Holder is new Ada.Containers.Indefinite_Holders (Element_Type);
type List;
procedure Push (L : in out List; E : Element_Type);
procedure All (L : List; Yield : not null access procedure (E : Element_Type));
function Gen_Fib return Iteration_Type (1);
private
type Element;
type Element_Access is access Element;
type Element is
record
Value : Element_Type;
Next : Element_Access;
end record;
type List is
record
Head : Element_Access;
Tail : Element_Access;
end record;
end Generic_Linked_List;
Next, we’ll implement the package body for the list and the iterator.
package body Generic_Linked_List is
type Element_Type is Integer; -- Define the element type as Integer
procedure Push (L : in out List; E : Element_Type) is
New_Element : Element_Access := new Element'(Value => E, Next => null);
begin
if L.Head = null then
L.Head := New_Element;
L.Tail := New_Element;
else
L.Tail.Next := New_Element;
L.Tail := New_Element;
end if;
end Push;
procedure All (L : List; Yield : not null access procedure (E : Element_Type)) is
Current : Element_Access := L.Head;
begin
while Current /= null loop
Yield (Current.Value);
Current := Current.Next;
end loop;
end All;
function Gen_Fib return Iteration_Type (1) is
procedure Fibonacci (Yield : not null access procedure (E : Integer)) is
(A, B : Integer := 1;
begin
loop
Yield (A);
(A, B) := (B, A + B);
end loop;
end Fibonacci;
My_Iter : Iteration_Type;
begin
My_Iter := Fibonacci'Access;
return My_Iter;
end Gen_Fib;
end Generic_Linked_List;
Using the List and Fibonacci Iterator
Now, let’s use the defined list and iterate over its elements. We will also demonstrate the generation of Fibonacci numbers.
with Ada.Text_IO; use Ada.Text_IO;
with Generic_Linked_List;
procedure Main is
package My_List is new Generic_Linked_List;
L : My_List.List;
procedure Print is
new Ada.Text_IO.Put_Line (Item => Integer'Image (Item => <>));
begin
My_List.Push (L, 10);
My_List.Push (L, 13);
My_List.Push (L, 23);
My_List.All (L, Print'Access);
Put_Line ("all: " & My_List.Collect (L)'Image);
for N in My_List.Gen_Fib loop
exit when N >= 10;
Put_Line (Integer'Image(N));
end loop;
end Main;
When compiling and running this Ada program:
$ gnatmake Main.adb
$ ./main
10
13
23
all: 10 13 23
1
1
2
3
5
8
Packages like Ada.Containers
provide a number of useful functions to work with iterators. For example, Collect
takes any iterator and collects all its values into an array or list.
Next example: Errors.