Функциональное программирование в 1С

28.03.19

Разработка - Универсальные функции

Статья о функциональном программировании в 1С. Добавляем новые возможности. Пример передачи функций в качестве аргумента.

Скачать файлы

Наименование Файл Версия Размер
Демо-пример функций первого и высшего порядка
.epf 7,71Kb
0
.epf 1 7,71Kb Скачать

В функциональном программировании есть такое понятие как функции первого класса (функции которые можно присваивать переменным, передавать в качестве аргументов и возвращать из функции). В 1С это также можно применять, используя небольшую вспомогательную функцию. Далее демо-пример ее использования.


&НаКлиенте
Процедура запуск(Команда)
	
	ТекстСообщения = "Результат вычисления с функцией delta = ";
	
	//вычислим значение константы с дельтой N*5
	deltaN5 = ВычислитьЗначениеСДельтой(Константа, newFunction("deltaN5", Новый Структура("N", N))); 
	Сообщить(СтрЗаменить(ТекстСообщения,"delta","deltaN5") + Строка(deltaN5)); 
	//Результат вычисления с функцией deltaN5 = 85
	
	//вычислим значение константы с дельтой N*M
	deltaNM = ВычислитьЗначениеСДельтой(Константа, newFunction("deltaNM", Новый Структура("N, M", N, M))); 
	Сообщить(СтрЗаменить(ТекстСообщения,"delta","deltaNM") + Строка(deltaNM));
	//Результат вычисления с функцией deltaNM = 55
	
КонецПроцедуры

//БЛОК ОСНОВНОЙ ПРОГРАММЫ

// Функция принимает в качестве аргументов значение константы и функцию вычисления дельты
//         функция выступает в роли функции высшего порядка
//
&НаКлиенте
Функция ВычислитьЗначениеСДельтой(Константа, functionDelta)

	//вычисление дельты, вызов функции
	Delta = callFunction(functionDelta);
	
	//основное вычисление
	Результат = Константа + Delta;
	
	Возврат Результат;

КонецФункции // ПеремножитьЧисла()

// Функция умножает переданное в аргументе значение на 5
//         функция выступает в роли функции первого класса
//
&НаКлиенте
Функция deltaN5(N)

	возврат N*5;

КонецФункции // ()

// Функция перемножает значения переданные в аргументах
//         функция выступает в роли функции первого класса
//
&НаКлиенте
Функция deltaNM(N, M)

	возврат N*M;

КонецФункции // ()

//БЛОК ВСПОМОГАТЕЛЬНЫХ ФУНКЦИЙ

// вспомогательная функция для инициации новой функции
//
// Параметры:
//  funcName  - Строка - Имя функции
//  arguments  - Структура - структура содержащая аргументы вызываемой функции
//                 аргументы должны быть расположены в том же порядке как в вызываемой функции
//
// Возвращаемое значение:
//   Структура   - набор содержащий имя функции и ее аргументы
//
&НаКлиенте
Функция newFunction(funcName, arguments)

	newFunction = Новый Структура("funcName, arguments", funcName, arguments);
	
	Возврат newFunction;

КонецФункции // newFunction()
 
// вспомогательный модуль вызова функций
//
// Параметры:
//	functionSet - Структура - Структура содержащая набор элементов для вызываемой функции
//		funcName  - Строка - Имя вызываемой функции
//		arguments  - Структура - структура содержащая аргументы вызываемой функции
//					аргументы должны быть расположены в том же порядке как в вызываемой функции 
//
// Возвращаемое значение:
//   Произвольный - возвращаемое значение вызываемой функции
&НаКлиенте
Функция callFunction(functionSet) 

	result = Неопределено;
	
	argumentsString = "";
	Для каждого argument Из functionSet.arguments Цикл
		argumentsString = argumentsString+"functionSet.arguments."+argument.Ключ+","; //раскладываем аргументы в строку
	КонецЦикла;
	
	argumentsString = Лев(argumentsString, СтрДлина(argumentsString)-1);
	
	СтрокаДляВыполнения = СтрЗаменить("result = funcName(arguments)", "funcName", functionSet.funcName);
	СтрокаДляВыполнения = СтрЗаменить(СтрокаДляВыполнения, "arguments", argumentsString);
	
	Выполнить(СтрокаДляВыполнения);
	
	Возврат result;

КонецФункции // func()

Обработка тестировалась на 1С:Предприятие 8.3 (8.3.13.1513)

Функциональное программирование Функции высшего порядка первого класса

См. также

Вставляем картинку из буфера обмена (платформа 1С 8.3.24)

Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Задача: вставить картинку из буфера обмена на форму средствами платформы 1С.

1 стартмани

18.03.2024    2670    0    John_d    8    

54

GUID в 1С 8.3 - как с ними быть

Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пришлось помучиться с GUID-ами немного, решил поделиться опытом, мало ли кому пригодится.

12.02.2024    4607    atdonya    22    

45

Переоткрытие внешних обработок

Универсальные функции Платформа 1С v8.3 Бесплатно (free)

На заключительных этапах, когда идет отладка или доработка интерфейса, необходимо много раз переоткрыть внешний объект. Вот один из способов автоматизации этого.

30.11.2023    3961    ke.92@mail.ru    16    

61

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    8821    YA_418728146    6    

141

Печать непроведенных документов для УТ, КА, ERP. Настройка печати по пользователям, документам и печатным формам

Пакетная печать Печатные формы Адаптация типовых решений Универсальные функции Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Абонемент ($m)

Расширение для программ 1С:Управление торговлей, 1С:Комплексная автоматизация, 1С:ERP, которое позволяет распечатывать печатные формы для непроведенных документов. Можно настроить, каким пользователям, какие конкретные формы документов разрешено печатать без проведения документа.

2 стартмани

22.08.2023    2071    21    progmaster    7    

3

Расширение: Быстрые отборы через буфер [Alt+C] Копировать список, [Alt+V] Вставить список, [Ctrl+C] Копировать из файлов

Инструментарий разработчика Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 1С:Розница 2 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Зарплата и Управление Персоналом 3.x Абонемент ($m)

Копирует в буфер значения из списков, из ячеек отчетов, таблиц, настроек списков, других отборов и вставляет в выбранную настройку отбора. Работает с Объект не найден. Работает как в одной так и между разными базами 1С. Использует комбинации [Alt+C] Копировать список, [Alt+V] Вставить список. Также для копирования данных используется стандартная [Ctrl+C] (например из открытого xls, mxl, doc и т.п. файла скопировать список наименований)

1 стартмани

13.10.2022    16143    133    sapervodichka    112    

129

Система контроля ведения учета [БСП]

Универсальные функции Механизмы типовых конфигураций БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

В данном материале рассмотрим типовой алгоритм подсистемы контроля учета БСП в конфигурациях на примерах.

18.07.2022    7243    quazare    8    

109
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. gzharkoj 502 28.03.19 14:38 Сейчас в теме
Как-то уже писали об этом https://infostart.ru/public/591496/.
Но это не функциональное программирование, это удобное использование метода Выполнить для частной задачи, эмулирующее подобие функционального стиля, на минимальной вложенности функций.
Chrizt; testnv0; wowik; alexey.kutya; +4 Ответить
2. Darklight 32 28.03.19 15:11 Сейчас в теме
(1)Согласен! Прелести функционального программирования именно в:
1. Декларативности (ну в большей степени чем классический императивный подход)
2. Развёртке кода (когда компилятор условно декларативные инструкции разворачивает в последовательность простых инструкций, попутно проводя оптимизацию, практически без падения производительности; заодно и распараллеливая выполнение при возможности)

Это позволяет писать алгоритмы достаточно компактно и, зачастую, более понятно (по времени на анализ), чем в императивном стиле (тем более в процедурном).

Эмуляция же этого процесса:
Во-первых, всё-равно будет выглядеть коряво (а не так красиво как это даёт истинный функциональный стиль)
Во-вторых, никакой оптимизиации тут не жди. Та же рекурсия, которая при функциональном программировании почти всегда разворачивается хотя бы в циклы (или даже просто в линейный поток команд, когда число итераций на момент запуска известно и не велико), то тут постоянный вызов операции "Выполнить" рано или поздно заполнит стек, не говоря уже о том, что код постоянно будет компилироваться в рантайме - а это время.
В-третьих, это замечание к операции "Выполнить" - она не поддерживается под iOS и в WEB-Клиенте, а если заменить её на "Вычислить" - всё равно не будет поддерживаться на iOS. Частично, вероятно (сам не проверял) обойти можно заменив её на "ВыполнитьОбработкуОповещения" - но тут тоже свои нюансы, как минимум, будет недоступно в серверном контексте.

В общем - функциональное программирование - это вообще-то очень мощная вещь, особенно с лямда-выражениями, но эмулировать её, по крайней мере вот так - это бред. А, вот, вариант с кодогерерацийе - мог бы быть более интересен: когда в функциональном стиле пишется декларативный код - он читается как строка и на его основе уже кодогенерируется код на языке 1С (или сразу байткод для стековой машины), со всей необходимой оптимизацией.
Chrizt; testnv0; alexey.kutya; +3 Ответить
4. alexey.kutya 301 28.03.19 15:19 Сейчас в теме
(2) понятно, что коряво, и ограничения в применении есть, но язык 1С не повзоляет большего (
5. Darklight 32 28.03.19 15:29 Сейчас в теме
(4)Вы просто не умеете его готовить. И не только сам язык, но и саму платформу - я дописал свой комментарий, который случайно разместил недописанным. Там, в конце я указал про кодогенерацию - это мощная штука и это вполне реализуемо - коли надо.

Но вообще-то, от 1С больше всего люди ждут хотя бы возможности вызывать функции, по ссылке на них (например переданной через аргументы другой функции) - что, в общем-то, вполне является атрибутом классического процедурного стиля программирования (без всяких там функций высших порядков, кэрринга и лямбда), но этого до сих пор нет в 1С (ну на клиенте это можно эмулировать через паттерн callback (я об этом написал), а вот на сервере - никак - только через "Вычислить", но серверный контекст мобильного приложения на iOS вообще никак не может позволить выполнять функции с не статически прописанными вызовами прямо в алгоритме).

Да и, в любом случае, функция должна быть экспортной - а в 1С функции по умолчанию приватные - что очень сильно мешает. Как и куча заморочек с контекстом выполнения (серверный/клиентский) с невозможность по-человечески его выбирать при вызове функций!
6. alexey.kutya 301 28.03.19 16:50 Сейчас в теме
(5)
Но вообще-то, от 1С больше всего люди ждут хотя бы возможности вызывать функции, по ссылке на них (например переданной через аргументы другой функции)

я в принципе это и реализовал
7. alexey.kutya 301 28.03.19 16:55 Сейчас в теме
(5)
Там, в конце я указал про кодогенерацию - это мощная штука и это вполне реализуемо - коли надо


Написать свой интерпретатор? Или я не так понял?
8. Darklight 32 28.03.19 17:58 Сейчас в теме
(7)Скорее написать свой компилятор - либо в код на языке 1С либо в байткод стековой машины 1С. Ну это чисто теоретические возможности того, как можно более эффективно привнести функциональное программирование в 1С. Я Вас к этому не призываю, хотя идея, безусловно очень интересная.
9. alexey.kutya 301 28.03.19 18:58 Сейчас в теме
(8)тогда скорее всего это будет транслятор. Хорошо, мы транслируем наш код в код 1С, и затем мы его должны каким-то образом выполнить, кроме как использовать тот же Выполнить() на ум ничего не приходит.
А если транслировать в байт-код, то как его отправить в стек выполнения? Может быть у вас есть информация на эту тему? Было бы интересно.
11. Darklight 32 29.03.19 10:21 Сейчас в теме
(9)Транслятор так транслятор (хотя это всё-таки кодогенератор или компилятор - смотря что на выходе). В первую очередь я имел в виду статическую трансляцию - динамическая нужна реже.
Хотя динамически тоже возможно - можно динамически создавать внешние обработки и использовать их в runtime - извращение ещё то - но это вполне реально.
Ну, или, если транслировать в язык 1С- то вызвать "Вычислить" однократно - это не тоже самое, что вызывать "Вычислить" сотни раз в секунду - ну Вы поняли, надеюсь, что я имею в виду.

На iOS только всё-равно не будут работать все динамические способы - таковы ограничения ОС.

Но, в любом случае, это всё извращение. Я Вас к этому не "подбиваю". Это скорее просто развлечение и разминка для ума, чем практическая задача.
12. alexey.kutya 301 29.03.19 11:19 Сейчас в теме
(11) этим я точно не буду заниматься ))
для меня очевидна высокая эффективность моего решения (для меня лично), с помощью одной маленькой функции (без многоэтажных конструкций), я придал функциональности языку 1С, а именно передавать функцию в аргументы другой функции
пусть это решение с ограничениями, но я это использую
и я не собираюсь это использовать для высоконагруженных систем, поэтому проблема производительности не на первом месте
23. so-quest 140 03.04.19 07:41 Сейчас в теме
(8) Года 4 назад было реализовано такое. Взяли Haxe и сгенерировали код на 1С
24. Darklight 32 03.04.19 14:06 Сейчас в теме
(23) Интересно. Вот бы ещё ссылочку на материалы на эту тему. Но, всё же, замечу, что Haxe - это больше императивный язык, чем функциональный (хоть и поддерживает некоторые фишки), но всё-равно - данная идея может быть интересной.
25. so-quest 140 03.04.19 15:30 Сейчас в теме
(24) Смотри - http://yoksel.net.ru/haxe1s

Вообще чисто функциональные языки в 1С - вредны с моей точки зрения. Ну или нужен некий компромисс как C#+F#
26. Darklight 32 03.04.19 16:05 Сейчас в теме
(25)За ссылку спасибо.

С остальным не спорю. Просто, если рассматривать трансляцию фуниконального языка в 1С, то в первую очередь, я воспринимаю этот как дополнение, как возможность написать блок кода внутри основного кода (или как отдельную подпрограмму т.е. процедуру, скажем, общего модуля), который выполнит некоторую алгоритмическую задачу, решение которой описать на функциональном языке гораздо эффективнее (понятнее, проще, при сохранении технической производительности), чем на императивном языке. И в итоге (условно при компиляции) этот функциональный блок будет заменён либо на императивные инструкции основного языка - либо сразу на байткод исполнительной машины)

Другой подход - это полный отказ от формирование программного кода на основном языке (ну хотя бы в рамках целого модуля, хотя так строго, конечно не обязательно) - и программирование всех алгоритмов на более продвинутом (поддерживающим различные современные парадигиы)- с последующей трансляцией всего алгоритма в форму, поддерживаемую базовой платформой, в достаточно высокопроизводиетльном виде (и пофиг уже на сложность итогового кода).

Hexe1s -хорош как "другой подход". Но.... чтобы это получило распространение.... нужно очень активное продвижение и использование в проектах! А это, почти не реально, если это не будет хот бы поощрять сама компания 1С - а она это делать не будет.
alexey.kutya; +1 Ответить
3. alexey.kutya 301 28.03.19 15:13 Сейчас в теме
(1) спасибо за ссылку, оказывается есть единомышленники ))
да, это эмуляция, но это работает
используется не для частной задачи
никто не мешает добавить вложенности функций
10. yarsort 140 29.03.19 09:20 Сейчас в теме
Как по мне, вещь бестолковая.
13. alexey.kutya 301 29.03.19 11:20 Сейчас в теме
(10)
Как по мне, вещь бестолковая.

согласен, каждому свое
14. ValeriVP 1303 29.03.19 17:46 Сейчас в теме
мне кажется не будет работать. параметры в структуре могут поменяться местами и будет облом.

но идея может заслуживать внимания.

поэтому мой вариант (не проверял на работоспособность):

#Область ПомогаторыРаботыСФунциямиВВидеПараметров

Функция НоваяФункция(ИмяФункции, Параметр1 = "_NaN_", Параметр2 = "_NaN_", Параметр3 = "_NaN_", Параметр4 = "_NaN_",
		Параметр5 = "_NaN_", Параметр6 = "_NaN_", Параметр7 = "_NaN_", Параметр8 = "_NaN_",
		Параметр9 = "_NaN_", Параметр10 = "_NaN_", Параметр11 = "_NaN_", Параметр12 = "_NaN_",
		Параметр13 = "_NaN_", Параметр14 = "_NaN_", Параметр15 = "_NaN_", Параметр16 = "_NaN_") Экспорт
	ПустойПараметр = "_NaN_";
	СтрокаПараметров = "";
	СтрокаПустыхПараметров = "";
	МассивПараметров = Новый Массив;
	Для н = 1 по 16 Цикл
		ЗначениеПараметра = Вычислить("Параметр" + н); 
		МассивПараметров.Добавить(ЗначениеПараметра);
		Если ЗначениеПараметра = ПустойПараметр тогда
			СтрокаПустыхПараметров = СтрокаПустыхПараметров + ", ";
		Иначе
			СтрокаПараметров = СтрокаПараметров + СтрокаПустыхПараметров + СтрШаблон(", Параметры[%1]", н - 1);	
			СтрокаПустыхПараметров = "";
		КонецЕсли;
	КонецЦикла;
	СтрокаПараметров = Сред(СтрокаПараметров, 3);
	ДанныеФункции = Новый Структура;
	ДанныеФункции.Вставить("МассивПараметров", МассивПараметров);
	ДанныеФункции.Вставить("СтрокаВызова", СтрШаблон("%1(%2)", ИмяФункции, СтрокаПараметров));
	
	Возврат ДанныеФункции;
 
КонецФункции

Функция ВызватьФункцию(ДанныеФункции) Экспорт
	Параметры = ДанныеФункции.МассивПараметров;
	Возврат Вычислить(ДанныеФункции.СтрокаВызова);
КонецФункции
 
 #КонецОбласти

Показать


Использовать:
ДанныеФункции = НоваяФункция("МойМодуль.МояЭкспортнаяФункция", Параметр1, ,,,, "ЕщеПараметр", ,,, "НуИЕще");
ВызватьФункцию(ДанныеФункции)
15. alexey.kutya 301 29.03.19 19:02 Сейчас в теме
(14) работать будет, но с условием что структура куда помещаются параметры не будет меняться
Ваша реализация тоже интересная, я попробую ее на следующей неделе
16. ValeriVP 1303 30.03.19 00:53 Сейчас в теме
(15) В общем случае порядок обхода ключей структуры в цикле не определен. Если на каком-то примере ваша реализация работает, это не значит, что будет работать всегда.
Вместе с тем, у вас в примере функции, для которых не важен порядок параметров и пример конечно работает.
17. alexey.kutya 301 30.03.19 11:45 Сейчас в теме
(16) да, это справедливое замечание, но я также использую и для функций где важен порядок, и там тоже работает, если структура с параметрами не изменяется после создания. Порядок обхода структуры соответствует порядку добавления свойств. Я планирую заменить структуру на массив, чтобы убрать эти ограничения.
18. alexey.kutya 301 01.04.19 11:54 Сейчас в теме
(14) ваш вариант рабочий, только поменял имя переменной на ПараметрыФункции (Параметры зарезервировано для формы)

Функция ВызватьФункцию(ДанныеФункции) Экспорт
    ПараметрыФункции = ДанныеФункции.МассивПараметров;
    Возврат Вычислить(ДанныеФункции.СтрокаВызова);
КонецФункции
21. ValeriVP 1303 01.04.19 14:32 Сейчас в теме
(18) на клиенте это не нужно - можно (и ИМХО нужно) использовать обработку оповещения
22. alexey.kutya 301 01.04.19 15:44 Сейчас в теме
(21) но в этом случае не будет эффекта callback функции, результат выполнения не вернется в точку вызова
19. alexey.kutya 301 01.04.19 11:57 Сейчас в теме
(14) Ваш вариант поудобнее будет.
Если не против, я заменю в публикации на ваш код?
20. ValeriVP 1303 01.04.19 14:29 Сейчас в теме
Оставьте свое сообщение