Баннеры

Зарисовки в функциональном стиле

Просмотров: 20718

С точки зрения функционального программирования PascalABC.NET - плохой язык. Однако, некоторые идеи, тем не менее, могут быть реализованы в функциональном стиле. На них и остановимся.

В качестве объекта изложения возьмем алгоритм получения следующего числа в цепочке в задаче 74 из проекта Эйлера.

Каждый следующий член цепочки получается из предыдущего как сумма факториалов его цифр:

1!+6!+9! =363601

169 → 363601 → 1454 → 169

Вначале разобьём целое на массив цифр. Сделаем это с помощью метода расширения для integer. Алгоритм - безобразно неоптимальный:

type 
  IntArray = array of integer;
  
function integer.ToDigits(): IntArray;
begin
  var s := Self.ToString();
  SetLength(Result,s.Length);
  for var i := 1 to s.Length do
    Result[i-1] := OrdUnicode(s[i])-OrdUnicode('0');
end;

Для массива целых составим метод расширения, вычисляющий сумму элементов:

function IntArray.Sum(): integer;
begin
  Result := 0;
  for var i := 0 to Self.Length-1 do
    Result += Self[i];
end;

Для вывода массива целых на экран расширим его тип методом Print:

procedure IntArray.Print;
begin
  for var i := 0 to Self.Length-1 do
    write(Self[i],' ');
end;

Наконец, напишем метод расширения для преобразования массива целых в массив целых, воздействуя на каждый элемент функцией, передаваемой в качестве параметра:

type 
  IntFun = function (i: integer): integer;
 
function IntArray.Map(f: IntFun): IntArray;
begin
  SetLength(Result,Self.Length);
  for var i := 0 to Self.Length-1 do
    Result[i] := f(Self[i]);
end;

Проверяем:

function fact(n: integer): integer;
begin
  Result := 1;
  for var i:=1 to n do
    Result *= i;
end;
 
begin
  var i := 145;
  writeln(i.ToDigits().Map(fact).Sum());
end. 

Выводится 145 (145=1!+4!+5!)

Выведем 4 члена цепочки, начинающейся со 169. Для этого реализуем функцию перехода к следующему элементу:

function Next(i: integer): integer;
begin
  Result := i.ToDigits().Map(fact).Sum();
end;

Наконец, реализуем для данного целого функцию получения цепочки целых с указанной функцией перехода к следующему элементу:

function integer.Take(f: IntFun; n: integer): IntArray;
begin
  SetLength(Result,n);
  Result[0] := Self;
  for var i:=1 to n-1 do
    Result[i] := f(Result[i-1]);
end;

Пробуем:

begin
  var i := 169;
  i.Take(Next,4).Print();
end.

Получаем цепочку из 4 элементов:

169 363601 1454 169 

Полный код программы - здесь.

К сожалению, код не столь красив ввиду отсутствия в PascalABC.NET полноценной реализации лямбда-функций.

яндекс

Новости

20.02.25. 28 – 29 марта 2025 г. Институт математики механики и компьютерных наук ЮФУ проводит пятую онлайн Всероссийскую научно-​методическую конференцию «Использование системы программирования Pas​cal​ABC​.NET в обучении программированию». Зарегистрироваться на конференцию можно здесь.

16.02.25 состоялась первая олимпиада на языке программирования PascalABC.NET среди учеников компьютерной школы мехмата ЮФУ. Опубликованы разбор задач 1 ступени и разбор задач 2 ступени.

07.01.25. Опубликован обзор языка Learn PascalABC.NET in Y minutes.

02.01.25. Вышла версия PascalABC.NET 3.10.2. Основное: константы [1,2,3] по умолчанию считаются массивами.

26.11.24. Вышла версия PascalABC.NET 3.10.1. Основное: новая эффективная реализация встроенных множеств set of T.