При слове ТРИЗ, часто вспоминают тезис "идеальная система — та, которой нет (а ее функция при этом выполняется)". Как хороший админ, который не появляется в офисе, а все при этом исправно работает.
Функция и система — критически важные понятия в ТРИЗ, говорят даже о функциональном стиле
Попробуем посмотреть, насколько органично идеи функционального
Функция
Функция — модель изменения свойства объекта функции ("изделия") носителем функции ("инструментом").
Инструмент — то, с помощью чего мы совершаем некую работу, т.е. что-то меняем. Как правило именно его требуется усовершенствовать или создать. Соответственно именно носитель функции обычно подразумевается под словом "система" во всех ТРИЗовских рассуждениях про оную.
Изделие — то, что мы изменяем (обрабатываем) при помощи инструмента.
Главная функция — потребительское свойство, ради удовлетворения которого создается техническая система.
Сама функция задается обычно простым глаголом, отражающим суть процесса (не специальным термином, чтобы не мешала инерция
Например: молоток перемещает гвоздь; метла перемещает мусор; кружка удерживает кофе; пылесос перемещает пыль; топливо перемещает ракету.
Рассмотрим, в частности, чашку с кофе.
Чашка удерживает кофе.
Носитель функции (инструмент) — чашка, объект функции — кофе, функция — удерживать.
-- Задаем типы входных данных и результата выполнения
-- Предположим, типы данных Чашки и Кофе уже где-то заданы
hold :: Cup -> Coffee -> Coffee
-- вызываем функцию hold - "удержать" с параметрами в виде конкретных чашки и кофе
cup `hold` coffee
Функция hold должна быть полиморфна, поскольку чашка может удерживать не только кофе и кофе можно налить не только в чашку:
-- На входе пара сущностей типа а и b, на выходе измененная сущность типа b
hold :: a -> b -> b
-- что будет, если налить кофе в термос
thermos `hold` coffee
-- что будет, если пролить кофе на рубашку
shirt `hold` coffee
Инструмент и изделие могут изменяться, а суть их взаимодействия, выраженная функцией, остается прежней. По статистике большинство парных функций между элементами технических систем можно описать тремя десятками глаголов (перемещать, удерживать, нагревать, поглощать, информировать и пр.). Каждый из них с точки зрения Haskell-реализации представляет собой полиморфную функцию. Как, впрочем, и остальные глаголы естественного языка.
Обратная функция
В реальном мире всегда есть и обратная функция — действие изделия на инструмент (третий закон Ньютона никто не отменял).
Например, обрабатываемый металл затупляет сверло, нерадивый ученик утомляет преподавателя, файл уменьшает свободное место на диске.
В примере с кофе он нагревает и пачкает чашку.
Как правило обратная функция нам вредит (износ инструмента, доп.затраты), однако в иных ситуациях мы можем извлечь из нее пользу. Например, погреть руки о теплую чашку, будучи в прохладном помещении.
hold:: a -> b -> b
warm :: a -> b -> b
cup `hold` coffee
coffee `warm` cup
Цепочки функций
В случае, когда число элементов системы больше двух (т.е., фактически, всегда) их рассматривают попарно, получая цепочки функций.
Например, на рисунке ниже рука несет (перемещает) поднос с чашкой, поднос удерживает чашку, чашка удерживает кофе.
((arm `move` wrist) `hold` cup) `hold` coffee
Избавимся от скобок, задав левую ассоциативность
infixl 9 hold
arm `move` wrist `hold` cup `hold` coffee
Запись на Haskell очень близка к записи на естественном языке.
И цепочка в обратную сторону: кофе нагревает чашку, чашка нагревает блюдце, блюдце нагружает руку.
infixl 9 warm, weight
coffee `warm` cup `warm` wrist `weight` arm
Понимание главной функции и взаимодействий между элементами позволяет оптимально выбрать границы системы, включить лишь то, что нужно для выполнения целевой задачи (ничего не упустив) и не усложнять модель сверх необходимого.
Система, которой нет ...
Нам нужна функция, точнее результат ее применения, а инструмент сам по себе не нужен. Это расходный материал, привлекаемый лишь в силу необходимости.
Удерживать кофе может джезва, чайник, термос, блюдце и стол и рубашка (если кофе неосторожно пролили).
Мы даже были бы не против, если кофе САМ себя удерживал. Как это происходит, например, с водой в невесомости на космической станции.
Однако на зацикленных формулировках вроде "кофе удерживает кофе" в ТРИЗ останавливаться не принято, поскольку она бесполезна с практической точки зрения — не дает информации об элементах, за счет которых достигается результат.
С точки зрения программирования такая рекурсивная формулировка плоха тем, что здесь нет условия окончания рекурсии.
Нужно уйти в глубину и указать какие именно части (подсистемы) обеспечивают выполнение функции.
Жидкость принимает в невесомости компактную форму за счет сил поверхностного натяжения. Т.о. более подходящим описанием ситуации будет: поверхностный слой удерживает внутренний объем кофе.
Можно представить весь объем кофе как матрешку слоев, каждый из которых удерживает друг друга. При этом основную работу делает внешний слой.
-- Пусть первый слой - поверхностный, пятый - самый глубокий
let coffee = [layer1, layer2, layer3, layer4, layer5]
head coffee `hold` tail coffee
Впрочем, если нам важно влияние слоев друг на друга (например, в плане поглощения света),
можно изобрести велосипед и описать последовательные взаимодействия явно.
Рекурсивная природа явления сохраниться, но за счет понимания взаимосвязей подсистем мы сможем задать условия выхода из рекурсии и обратить ее себе на службу.
-- Функция "удерживать", которая выводит свою полную формулировку
hold :: String -> String -> String
hold tool "" = tool
hold tool workpiece = tool ++ " -> holds -> " ++ workpiece
-- Функция "удерживать себя".
-- Принимает на вход нарезанный слоями объект и
-- последовательно вызывает обычную функцию "удержать"
-- для каждого слоя и оствшегося объема
selfHold :: [String] -> String
selfHold [] = ""
selfHold (x:xs) = x `hold` selfHold xs
-- запускаем самоудержание трехслойного объекта
selfHold ["Layer1","Layer2","Layer3"]
в итоге получим
Layer1 -> holds -> Layer2 -> holds -> Layer3
Рекурсивность реализации никуда не исчезла, но стала конструктивной, а не бессмысленно зацикленной.
Тоже самое можно записать и короче, через свертку списка:
foldl1 hold ["Layer1","Layer2","Layer3"]
Заключение
Видение технической системы как ткани из функций, связывающих ее во едино и определяющих суть и предназначение, чрезвычайно роднит ТРИЗ с функциональными языками программирования, в которых функция — основная управляющая конструкция.
Рассмотренный подход служит хорошим подспорьем в плане декомпозиции задачи и управления сложностью модели.
Автор: shbma