====== Использование процедурных типов ====== Суть этой возможности в **Компонентном Паскале** состоит в том, что можно создать //переменную//, которой позже можно присвоить //адрес// какой-либо //процедуры//, после чего, можно использовать эту переменную как саму процедуру. При этом, нужно помнить, что **список аргументов** у //переменной процедурного типа// и самой //процедуры// **должны** совпадать. Ниже приведён пример программы, которая складывает и перемножает все целые числа в массиве, а также проверяет, отсортирован ли массив целых чисел по возрастанию или убыванию. Для этого используются: - Процедура ReduceLong, из названия и описания которой можно понять, что происходит [[https://ru.wikipedia.org/wiki/Свёртка_списка|свёртка]] массива целых чисел с результатом LONGINT. В данную процедуру передаётся массив целых чисел и процедура с сигнатурой процедурного типа CalculatorLong. Для примера были созданы процедуры Add, Sub, Mul, Div с такой сигнатурой. - Процедура ReduceBool, которая производит свёртку массива целых чисел и возвращает булево значение. В данную процедуру передаётся массив целых чисел и процедура с сигнатурой процедурного типа CalculatorBool. Для примера были созданы процедуры Greater и Less с такой сигнатурой. ==== Пример ==== MODULE FunctionalCalculator; IMPORT Out := StdLog; TYPE CalculatorLong = PROCEDURE (VAR acc: LONGINT; cur: INTEGER); CalculatorBool = PROCEDURE (VAR acc: BOOLEAN; a, b: INTEGER); PROCEDURE Add(VAR acc: LONGINT; cur: INTEGER); BEGIN acc := acc + cur END Add; PROCEDURE Sub(VAR acc: LONGINT; cur: INTEGER); BEGIN acc := acc - cur END Sub; PROCEDURE Mul(VAR acc: LONGINT; cur: INTEGER); BEGIN acc := acc * cur END Mul; PROCEDURE Div(VAR acc: LONGINT; cur: INTEGER); BEGIN acc := acc DIV cur END Div; PROCEDURE Greater(VAR acc: BOOLEAN; a, b: INTEGER); BEGIN acc := acc & (a > b) END Greater; PROCEDURE Less(VAR acc: BOOLEAN; a, b: INTEGER); BEGIN acc := acc & (a < b) END Less; PROCEDURE ReduceLong(IN nums: ARRAY OF INTEGER; c: CalculatorLong): LONGINT; VAR i: INTEGER; acc: LONGINT; BEGIN acc := nums[0]; FOR i := 1 TO LEN(nums) - 1 DO c(acc, nums[i]) END; RETURN acc; END ReduceLong; PROCEDURE ReduceBool(IN nums: ARRAY OF INTEGER; c: CalculatorBool): BOOLEAN; VAR i: INTEGER; acc: BOOLEAN; BEGIN acc := TRUE; i := 1; REPEAT c(acc, nums[i-1], nums[i]); INC(i); UNTIL (i = LEN(nums)) OR ~acc; RETURN acc; END ReduceBool; PROCEDURE Start*; VAR sn: ARRAY 5 OF INTEGER; (* sn - some nums *) orderedNums: ARRAY 3 OF INTEGER; sum, mul: LONGINT; greater, less: BOOLEAN; BEGIN sn[0] := 1; sn[1] := 3; sn[2] := 5; sn[3] := 7; sn[4] := 9; sum := ReduceLong(sn, Add); Out.String('sum = '); Out.Int(sum); Out.Ln; mul := ReduceLong(sn, Mul); Out.String('mul = '); Out.Int(mul); Out.Ln; orderedNums[0] := 7; orderedNums[1] := 5; orderedNums[2] := 1; greater := ReduceBool(orderedNums, Greater); Out.String('greater = '); Out.Bool(greater); Out.Ln; less := ReduceBool(orderedNums, Less); Out.String('less = '); Out.Bool(less); Out.Ln; END Start; END FunctionalCalculator. ==== Важные замечания ==== Если переменной процедурного типа не присвоить значение, она будет иметь значение **NIL**.