TRIZ, Haskell e pensamento funcional

Na palavra TRIZ, muitas vezes recordamos a tese "um sistema ideal é aquele que não existe (e sua função é cumprida)". Como um bom administrador que não aparece no escritório, mas tudo está funcionando corretamente.


Função e sistema são conceitos críticos no TRIZ, eles até falam de um estilo funcional de pensamento. É verdade que, com essas palavras, eu pessoalmente me associo imediatamente a linguagens de programação funcional.


Vamos tentar ver como organicamente as idéias do pensamento funcional do TRIZ são exibidas em Haskell, uma das linguagens funcionais puras de uso geral.



Função


Função - um modelo de alteração da propriedade de um objeto de função ("produto") por um portador de função ("ferramenta").


Uma ferramenta é algo com o qual fazemos algum trabalho, ou seja, Estamos mudando alguma coisa. Como regra, é isso que precisa ser aprimorado ou criado. Consequentemente, é o portador da função que geralmente se entende pela palavra "sistema" em todos os argumentos do TRIZ sobre o assunto.


Um produto é o que mudamos (processamos) com uma ferramenta.



A principal função é uma propriedade do consumidor, para a qual um sistema técnico é criado.


A função em si é geralmente definida por um verbo simples, refletindo a essência do processo (não um termo especial, para não interferir na inércia do pensamento), o portador e o objeto da função são incluídos na formulação.


Por exemplo: um martelo move um prego; uma vassoura move lixo; a caneca segura café; o aspirador de pó move a poeira; combustível move o foguete.


Considere, em particular, uma xícara de café.
Uma xícara contém café.
O portador da função (ferramenta) é uma xícara, o objeto da função é café, a função é segurar.



--        -- ,       -  hold :: Cup -> Coffee -> Coffee --   hold - ""         cup `hold` coffee 

A função de retenção deve ser polimórfica, pois uma xícara pode conter não apenas café e o café pode ser derramado não apenas em uma xícara:


 --        b,      b hold :: a -> b -> b --  ,      thermos `hold` coffee --  ,      shirt `hold` coffee 

A ferramenta e o produto podem mudar, e a essência de sua interação, expressa pela função, permanece a mesma. Segundo as estatísticas, a maioria das funções de par entre elementos de sistemas técnicos pode ser descrita por três dúzias de verbos (mover, segurar, aquecer, absorver, informar, etc.). Cada um deles, do ponto de vista da implementação de Haskell, é uma função polimórfica. Como, no entanto, o resto dos verbos da linguagem natural.


Função inversa


No mundo real, sempre há a função oposta - a ação do produto no instrumento (ninguém cancelou a terceira lei de Newton).



Por exemplo, o metal que está sendo processado embota a broca, um aluno descuidado cansa o professor e o arquivo reduz o espaço livre em disco.
No exemplo do café, ele aquece e suja a xícara.



Como regra, a função inversa nos prejudica (desgaste da ferramenta, custos adicionais), mas em outras situações podemos nos beneficiar disso. Por exemplo, aqueça as mãos em uma xícara quente enquanto estiver em uma sala fria.


 hold:: a -> b -> b warm :: a -> b -> b cup `hold` coffee coffee `warm` cup 

Cadeias de funções


No caso em que o número de elementos do sistema é superior a dois (ou seja, sempre), eles são considerados em pares, recebendo cadeias de funções.


Por exemplo, na figura abaixo, uma mão carrega (move) uma bandeja com uma xícara, uma bandeja segura uma xícara e uma xícara segura café.



 ((arm `move` wrist) `hold` cup) `hold` coffee 

Remova os parênteses especificando a associatividade esquerda


 infixl 9 hold arm `move` wrist `hold` cup `hold` coffee 

A gravação em Haskell está muito próxima da gravação em linguagem natural.


E a corrente na direção oposta: o café aquece a xícara, a xícara aquece o pires, o pires carrega a mão.


 infixl 9 warm, weight coffee `warm` cup `warm` wrist `weight` arm 

Compreender a função principal e as interações entre os elementos permite escolher da melhor maneira os limites do sistema, incluir apenas o necessário para concluir a tarefa de destino (sem perder nada) e não complicar o modelo além do necessário.


Um sistema que não existe ...


Precisamos de uma função, ou melhor, do resultado de sua aplicação, e a ferramenta em si não é necessária. Este é um consumível, atraído apenas pela necessidade.


O café pode ser guardado por um cezve, bule, garrafa térmica, pires e mesa e camisa (se o café for derramado inadvertidamente).


Nós nem nos importaríamos se o próprio café se sustentasse. Como isso acontece, por exemplo, com água em gravidade zero em uma estação espacial.



No entanto, não é habitual recorrer a formulações em loop como “café contém café” no TRIZ, uma vez que é inútil do ponto de vista prático - ele não fornece informações sobre os elementos pelos quais o resultado é alcançado.


Do ponto de vista da programação, essa formulação recursiva é ruim, pois não há condição para encerrar a recursão.


É necessário ir mais fundo e indicar quais partes (subsistemas) fornecem o cumprimento da função.


O líquido assume uma forma compacta em gravidade zero devido às forças de tensão superficial. T.O. uma descrição mais apropriada da situação seria: a camada superficial retém o volume interno do café.


Você pode imaginar todo o volume de café como uma matryoshka de camadas, cada uma das quais se mantém. Nesse caso, o trabalho principal é realizado pela camada externa.



 --    - ,  -   let coffee = [layer1, layer2, layer3, layer4, layer5] head coffee `hold` tail coffee 

No entanto, se é importante para nós que as camadas se influenciem (por exemplo, em termos de absorção de luz),
pode-se inventar uma bicicleta e descrever interações seqüenciais explicitamente.


A natureza recursiva do fenômeno é preservada, mas, ao entender as interconexões dos subsistemas, podemos definir as condições para a saída da recursão e transformá-la em nosso serviço.



 --  "",      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"] 

no final, chegamos


Camada1 -> retenções -> Camada2 -> retenções -> Camada3

A recursividade da implementação não desapareceu em lugar algum, mas tornou-se construtiva e não obcecada sem sentido.


O mesmo pode ser escrito resumidamente, através da convolução da lista:


 foldl1 hold ["Layer1","Layer2","Layer3"] 

Conclusão


A visão de um sistema técnico como uma estrutura de funções que o une e determina a essência e o objetivo do TRIZ está extremamente relacionada ao TRIZ com linguagens de programação funcionais, nas quais uma função é a principal estrutura de controle.


A abordagem considerada é uma boa ajuda em termos de decomposição do problema e controle da complexidade do modelo.

Source: https://habr.com/ru/post/pt414929/


All Articles