Магия Ада
Речь, конечно, о магии языка Ада.
Возможно, это восторг неофита, но тем не менее. Недели две назад я решил погрузиться в язык Ada. Он вполне вписывается в мои предпочтения: компилируемый, строго (точнее, очень строго) типизированный, со сборщиком мусора. По таким критериям сегодня выбор достаточно широк, я хорошо отношусь к C# и Go.
Ada позволяет объявить модульный тип, то есть тип с ограниченной длиной. Потом на основании такого типа можно создавать массивы, которые «закольцованы», то есть в таких массивах невозможно выйти за его границу.
Нам нужно, например, подсчитать длины сторон треугольника.
Объявление
Мы объявляем тип Indextype длиной 3, а также объявляем структуру точки и функцию расстояния между двумя точками.
WITH Ada.Text_Io; PACKAGE Geometry IS TYPE Indextype IS MOD 3; PACKAGE Index_Io IS NEW Ada.Text_Io.Modular_Io (Num => Indextype); TYPE Point IS RECORD X, Y : FLOAT := 0.0; Index : INTEGER := 0; END RECORD; FUNCTION Get_Distance (M, N : POINT) RETURN FLOAT; PROCEDURE Put (P : POINT); END Geometry;
Детали реализации
В самой тестовой программе создаём переменную Index модульного типа, объявленного в пакете Geometry. Объявляем тип «треугольник»: массив точек длиной, равной размерности типа Indextype (по-моему, это очень здорово).
Для начала заполняем массив точек случайными координатами и выводим их на экран.
WITH Ada.Numerics.Elementary_Functions; WITH Ada.Float_Text_Io; WITH Ada.Integer_Text_Io; WITH Ada.Text_Io; USE Ada.Numerics.Elementary_Functions; PACKAGE BODY Geometry IS FUNCTION Get_Distance (M, N : POINT) RETURN FLOAT IS BEGIN RETURN Sqrt (FLOAT ((N.X - M.X)**2) + FLOAT ((N.Y - M.Y)**2)); END Get_Distance; PROCEDURE Put (P : POINT) IS BEGIN Ada.Text_Io.Put ("Point"); Ada.Integer_Text_Io.Put (P.Index); Ada.Text_Io.Put (": "); Ada.Text_Io.Put ("p.X is"); Ada.Float_Text_Io.Put (P.X, Aft => 4, Exp => 0); Ada.Text_Io.Put (", p.Y is"); Ada.Float_Text_Io.Put (P.Y, Aft => 4, Exp => 0); Ada.Text_Io.New_Line; END Put; END Geometry;
Тестовая программа
И в самом конце самое интересное: мы можем пройтись итератором по всему диапазону (размерности) типа Indextype, и для каждого случая подсчитать расстояние между текущей и следующей точкой, а также любой другой, используя ±N; в языке типа C++ мы не cможем, находясь на последней позиции массива, взять значение из позиции «текущая + 1». Здесь же — легко и просто.
-- This program fills an array with three points with random coordinates -- and then calculates the distances between them. WITH Ada.Float_Text_Io; WITH Ada.Integer_Text_Io; WITH Ada.Text_Io; WITH Ada.Numerics.Float_Random; WITH Geometry; USE Geometry; PROCEDURE Getline IS Index : Geometry.INDEXTYPE := 0; Seed : Ada.Numerics.Float_Random.GENERATOR; TYPE Triangle IS ARRAY (Geometry.INDEXTYPE'Range) OF Geometry.POINT; Tri : TRIANGLE; BEGIN Ada.Numerics.Float_Random.Reset (Seed); FOR I IN Geometry.INDEXTYPE'Range LOOP Tri (I) := (X => Ada.Numerics.Float_Random.Random (Seed) * 10.0, Y => Ada.Numerics.Float_Random.Random (Seed) * 10.0, Index => INTEGER (I)); END LOOP; FOR I IN Geometry.INDEXTYPE'Range LOOP Geometry.Put (Tri (I)); Geometry.Put (Tri (I + 1)); Ada.Text_Io.Put ("Distance between points"); Ada.Integer_Text_Io.Put (Tri (I).Index, Width => 2); Ada.Text_Io.Put (" and "); Ada.Integer_Text_Io.Put (Tri (I + 1).Index, Width => 2); Ada.Text_Io.Put (" is "); Ada.Float_Text_Io.Put (Geometry.Get_Distance (Tri (I + 1), Tri (I)), Aft => 4, Exp => 0); Ada.Text_Io.New_Line (2); END LOOP; END Getline;
Делаем gnatmake getline && getline, вывод программы будет приблизительно таким:
Point 0: p.X is 4.5906, p.Y is 9.9080 Point 1: p.X is 3.4309, p.Y is 8.8065 Distance between points 0 and 1 is 1.5994 Point 1: p.X is 3.4309, p.Y is 8.8065 Point 2: p.X is 9.1367, p.Y is 9.4752 Distance between points 1 and 2 is 5.7448 Point 2: p.X is 9.1367, p.Y is 9.4752 Point 0: p.X is 4.5906, p.Y is 9.9080 Distance between points 2 and 0 is 4.5667