A programação funcional aumenta a 'lacuna representacional' entre problemas e soluções? [fechadas]

18

Como as linguagens de máquina (por exemplo, 0110101000110101) as linguagens de computador geralmente evoluíram para formas mais altas de abstração, facilitando a compreensão do código quando aplicado a um problema. Assembler era uma abstração sobre código de máquina, C era uma abstração sobre assembler, etc.

O design orientado a objetos parece ser muito bom para nos permitir modelar um problema em termos de objetos, por exemplo, o problema de um sistema de inscrição em um curso universitário pode ser modelado com uma Courseclasse, uma Studentclasse etc. Então, quando escrevemos a solução em uma linguagem OO, temos classes semelhantes que recebem responsabilidades e que geralmente são úteis para o design, especialmente para modularizar o código. Se eu der esse problema a 10 equipes independentes que o resolverem com um método OO, geralmente as 10 soluções terão as classes relacionadas ao problema em comum. Pode haver muitas diferenças quando você começa a entrar no acoplamento e nas interações dessas classes; portanto, não existe "diferença de representação zero".

Minha experiência com programação funcional é muito limitada (sem uso no mundo real, apenas programas do tipo Hello World). Não estou conseguindo ver como essas linguagens permitem o mapeamento fácil de soluções de FP para problemas (com uma baixa diferença de representação) da mesma forma que as linguagens OO.

Entendo as vantagens do FP em relação à programação simultânea. Mas estou faltando alguma coisa ou a FP não se resume a reduzir uma lacuna representacional (tornando as soluções mais fáceis de entender)?

Outra maneira de perguntar: o código FP de 10 equipes diferentes que resolvem o mesmo problema do mundo real tem muito em comum?


Da Wikipedia sobre Abstração (ciência da computação) (ênfase minha):

Linguagens de programação funcional geralmente exibem abstrações relacionadas a funções , como abstrações lambda (transformando um termo em uma função de alguma variável), funções de ordem superior (parâmetros são funções), abstração de colchetes (transformando um termo em uma função de uma variável).

A lacuna representacional pode ser potencialmente aumentada, porque [alguns] problemas do mundo real não são modelados facilmente com tais abstrações.


Outra maneira que vejo diminuindo a lacuna representacional é rastrear os elementos da solução de volta ao problema. O 0's e 1s em código de máquina é muito difícil de rastrear, enquanto que a Studentclasse é fácil de rastrear. Nem todas as classes OO rastreiam facilmente para o espaço do problema, mas muitas o fazem.

As abstrações de FP não precisam sempre ser explicadas para descobrir qual parte do espaço do problema está resolvendo (além dos problemas de matemática )?OK - Eu sou bom nessa parte. Depois de examinar muitos outros exemplos, vejo como as abstrações de FP são muito claras para partes do problema que são expressas no processamento de dados.


A resposta aceita para uma pergunta relacionada A UML pode ser usada para modelar um programa Funcional? - diz "Programadores funcionais não têm muito uso para diagramas". Realmente não me importo se é UML, mas me faz pensar em abstrações de FP fáceis de entender / comunicar, se não houver diagramas amplamente usados ​​(assumindo que esta resposta esteja correta). Novamente, meu nível de uso / entendimento de FP é trivial, então não entendo a necessidade de diagramas em programas simples de FP.

O design do OO possui níveis de abstração de função / classe / pacote, com encapsulamento (controle de acesso, ocultação de informações) em cada um, o que facilita o gerenciamento da complexidade. Esses são elementos que permitem ir do problema para a solução e voltar mais facilmente.


Muitas respostas falam de como a análise e o design são feitos no FP de maneira análoga à OO, mas ninguém cita nada de alto nível até agora (paul citou algumas coisas interessantes, mas é de baixo nível). Ontem eu pesquisei bastante no Google e encontrei uma discussão interessante. O seguinte é de refatoração de programas funcionais de Simon Thompson (2004) (ênfase minha)

Ao projetar um sistema orientado a objetos, é dado como certo que o projeto precederá a programação. Os projetos serão gravados usando um sistema como UML, suportado em ferramentas como o Eclipse. Programadores iniciantes podem muito bem aprender uma abordagem de design visual usando sistemas como o BlueJ. O trabalho sobre uma metodologia semelhante para programação funcional é relatado no FAD: Functional Analysis and Design , mas existe pouco outro trabalho. Pode haver várias razões para isso.

  • Os programas funcionais existentes são de uma escala que não requer design. Muitos programas funcionais são pequenos, mas outros, como o Glasgow Haskell Compiler, são substanciais.

  • Os programas funcionais modelam diretamente o domínio do aplicativo, tornando o design irrelevante. Embora as linguagens funcionais forneçam uma variedade de abstrações poderosas, é difícil argumentar que elas fornecem todas e apenas as abstrações necessárias para modelar o mundo real.

  • Programas funcionais são construídos como uma série de protótipos em evolução.

Na tese de doutorado citada acima , os benefícios do uso de metodologias de análise e design (ADM) são destacados independentemente dos paradigmas. Mas é argumentado que as ADMs devem se alinhar ao paradigma de implementação. Ou seja, o OOADM funciona melhor para a programação OO e não é bem aplicado a outro paradigma como o FP. Aqui está uma ótima citação que eu acho que parafraseia o que chamo de gap representacional:

pode-se argumentar longamente sobre qual paradigma fornece o melhor suporte para o desenvolvimento de software, mas obtém-se o pacote de desenvolvimento mais natural, eficiente e eficaz quando se permanece dentro de um único paradigma, desde a descrição do problema até a implementação e entrega.

Aqui está o conjunto de diagramas propostos pelo FAD:

  • diagramas de dependência de função que apresentam uma função com aqueles que utiliza em sua implementação;
  • diagrama de dependência de tipos que fornece o mesmo serviço para tipos; e,
  • diagramas de dependência de módulo que apresentam vistas da arquitetura do módulo do sistema.

Há um estudo de caso na seção 5.1 da tese do FAD, que é um sistema para automatizar a produção de dados relacionados a uma liga de futebol. Os requisitos são 100% funcionais, por exemplo, entrada de resultados de futebol, tabelas de classificação, tabelas de pontuação, tabelas de presença, transferência de jogadores entre equipes, atualização de dados após novos resultados, etc. Nenhuma menção de como o FAD trabalha para resolver requisitos não funcionais está documentada , além de afirmar que "nova funcionalidade deve ser permitida a um custo mínimo", algo quase impossível de testar.

Infelizmente, além do FAD, não vejo referências modernas para linguagens de modelagem (visuais) propostas para o FP. A UML é outro paradigma, por isso devemos esquecer isso.

Fuhrmanator
fonte
1
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
maple_shaft

Respostas:

20

Os dados básicos estão estruturados da mesma forma em praticamente qualquer paradigma. Você terá a Student, a Course, etc., seja um objeto, uma estrutura, um registro ou qualquer outra coisa. A diferença com OOP não é como os dados são estruturados, é como as funções são estruturadas.

Na verdade, acho que os programas funcionais correspondem muito mais à minha opinião sobre um problema. Por exemplo, para planejar a programação de um aluno para o próximo semestre, você pensa em coisas como listas de cursos que um aluno concluiu, cursos em um programa de graduação, cursos oferecidos neste semestre, cursos para os quais os alunos concluíram pré-requisitos, cursos com horários que não entre em conflito etc.

De repente, não está tão claro qual classe deve criar e armazenar todas essas listas. Ainda menos quando você tem combinações complexas dessas listas. No entanto, você deve escolher uma classe.

No FP, você escreve funções que recebem um aluno e uma lista de cursos e retornam uma lista filtrada de cursos. Você pode agrupar todas essas funções em um módulo. Você não precisa associá-lo a uma aula ou a outra.

Portanto, seus modelos de dados acabam parecendo mais com a maneira como os programadores de POO pensam em seus modelos, antes de serem poluídos por classes que não têm outro objetivo além de fornecer locais convenientes para colocar funções que operam em combinações de outras classes. Não há CourseStudentFilterListclasses estranhas ou similares que você sempre precise no OOP, mas nunca pense no design inicial.

Karl Bielefeldt
fonte
5
@BenAaronson o problema na minha experiência é que, então qualquer função relacionada com um aluno é adicionado à classe Student e suas responsabilidades crescer e crescer até que você precisa para introduzir StudentCourseFiltererpara manter as coisas gerenciável
AlexFoxGill
3
As abordagens @Den Hybrid têm seus méritos. Não é verdade, no entanto, que a distinção seja artificial. Existem muitos compromissos que a Scala teve que fazer para se ajustar ao OOP e FP (a inferência de tipo menos poderosa é uma. Complexidade é outra: sim, uma linguagem que mistura OOP e FP tende a ser mais complexa - como em "difícil de usar" e entender "- que um de seus irmãos mais puros nos dois extremos).
Andres F.
3
@Den Veja também a programação "Mostly Functional" de Erik Meijer não funciona " , que argumenta contra a abordagem híbrida e para obter um FP" fundamentalista "completo.
26515 Andres F.
4
@ Den A popularidade que você descreve é, receio, um acidente histórico. Eu uso Scala no trabalho, e é uma fera complexa devido à maneira como tenta misturar FP e OOP. Mudar para uma linguagem FP verdadeira como Haskell parece uma lufada de ar fresco - e também não estou falando de uma perspectiva acadêmica!
Andrés F.
3
@ Den Não sei dizer o que uma dessas funções faz. No entanto, posso dizer se a primeira função no FP era uma classificação ou um filtro, seria denominada filtro ou classificação , não func(exatamente como você nomeou IFilter, etc). Em geral, no FP, você o nomearia funcou fquando sortou filteré uma opção válida! Por exemplo, ao escrever uma função de ordem superior que aceita funccomo parâmetro.
Andrés F.
10

Quando participei da minha aula de Java anos atrás, era esperado que mostrássemos nossas soluções para toda a turma, então pude ver como as pessoas pensam; como eles resolvem problemas logicamente. Eu esperava que as soluções agrupassem em torno de três ou quatro soluções comuns. Em vez disso, observei 30 alunos resolverem o problema de 30 maneiras completamente diferentes.

Naturalmente, à medida que os programadores iniciantes ganham experiência, eles ganham exposição a padrões comuns de software, começam a usar esses padrões em seu código e, em seguida, suas soluções podem se unir em torno de algumas estratégias ótimas. Esses padrões formam uma linguagem técnica pela qual desenvolvedores experientes podem se comunicar.

A linguagem técnica subjacente à programação funcional é a matemática . Consequentemente, os problemas mais adequados para resolver usando a programação funcional são essencialmente problemas matemáticos. Pela matemática, não estou me referindo ao tipo de matemática que você veria nas soluções de negócios, como adição e subtração. Em vez disso, estou falando sobre o tipo de matemática que você pode ver no Math Overflow, ou o tipo de matemática que você veria no mecanismo de pesquisa do Orbitz (escrito em Lisp).

Essa orientação tem algumas ramificações importantes para programadores funcionais que tentam resolver problemas de programação do mundo real:

  1. A programação funcional é mais declarativa do que imperativa; preocupa-se principalmente em dizer ao computador o que fazer, não como fazê-lo.

  2. Os programas orientados a objetos são geralmente criados de cima para baixo. Um design de classe é criado e os detalhes são preenchidos. Os programas funcionais geralmente são criados de baixo para cima, começando com pequenas funções detalhadas que são combinadas em funções de nível superior.

  3. A programação funcional pode ter vantagens na criação de protótipos de lógica complexa, na construção de programas flexíveis que podem mudar e evoluir organicamente e na criação de software onde o design inicial não é claro.

  4. Os programas orientados a objetos podem ser mais adequados para domínios de negócios, porque as classes, as mensagens entre os objetos e os padrões de software fornecem uma estrutura que mapeia o domínio de negócios, captura sua inteligência de negócios e a documenta.

  5. Como todo software prático produz efeitos colaterais (E / S), as linguagens de programação puramente funcionais exigem um mecanismo para produzir esses efeitos colaterais, permanecendo matematicamente puros (mônadas).

  6. Os programas funcionais podem ser mais facilmente comprovados, devido à sua natureza matemática. O sistema de tipos de Haskell pode encontrar coisas em tempo de compilação que a maioria das linguagens OO não consegue.

E assim por diante. Como em muitas coisas na computação, as linguagens orientadas a objetos e as linguagens funcionais têm vantagens e desvantagens.

Algumas linguagens OO modernas adotaram alguns dos conceitos úteis de programação funcional, para que você possa ter o melhor dos dois mundos. O Linq, e os recursos de idioma que foram adicionados para suportá-lo, são um bom exemplo disso.

Robert Harvey
fonte
6
@ thepacker: Você tem estado na programação funcional. Somente a representação é diferente: no OOP você usa variáveis ​​mutáveis, enquanto na programação funcional você pode usar fluxos infinitos de estados que são criados dinamicamente quando o programa precisa inspecioná-los. Infelizmente, o estado é frequentemente identificado com variáveis ​​mutáveis, como se as variáveis ​​mutáveis ​​fossem a única maneira de representar o estado. Como conseqüência, muitos acreditam que uma linguagem de programação sem variáveis ​​mutáveis ​​não pode modelar o estado.
Giorgio
12
"Consequentemente, os problemas que são mais adequados para resolver usando programação funcional são essencialmente problemas matemáticos.": Eu não concordo com esta afirmação (veja também meu comentário anterior), pelo menos não vejo por que deveria ser verdade ou o que na verdade significa. Você pode ver atravessando uma estrutura de diretórios como um problema de matemática e implementá-la com uma função recursiva, mas como o cliente não vê o código-fonte, você está apenas resolvendo um problema prático, como encontrar um arquivo em algum lugar do sistema de arquivos. Acho essa distinção artificial entre problemas matemáticos e não matemáticos.
Giorgio
5
+1, mas não sou vendido nos pontos 2 e 4. Vi vários tutoriais e postagens do blog da Haskell que começam abordando um problema de cima para baixo, definindo todos os tipos e operações para ver como tudo se encaixa enquanto deixando cada definição de valor e função indefinida (bem, definida para lançar uma exceção). Parece-me que os programadores Haskell tendem a modelar o problema mais detalhadamente porque estão mais inclinados a adicionar tipos triviais para fins semânticos - por exemplo, adicionar um SafeStringtipo para representar seqüências de caracteres que escaparam ao HTML - e geralmente controlam mais efeitos
Doval
4
"os problemas mais adequados para resolver usando a programação funcional são essencialmente problemas matemáticos". Isso simplesmente não é verdade. O fato de o conceito de mônadas advir da teoria das categorias também não significa que as tarefas matemáticas são o domínio mais natural / adequado para linguagens funcionais. Tudo o que isso significa é que o código escrito em linguagens funcionais fortemente tipadas pode ser descrito, analisado e fundamentado sobre o uso da matemática. Esse é um recurso extra poderoso, não algo que impede você de escrever "Barbie Horse Adventures" em Haskell.
precisa saber é
6
@itsbruce A Barbie Horse Adventures é uma simulação matemática séria do mais alto calibre, é a aplicação de FP em projeções numéricas excessivamente complexas, como matrizes que descrevem o brilho físico dos cabelos da Barbie durante um período discreto em uma variedade de possíveis ambientes do mundo real que convencem as pessoas a descarta-o completamente como irrelevante para a codificação diária de problemas de negócios.
Jimmy Hoffa
7

Gostaria de enfatizar um aspecto que considero importante e que não foi abordado nas outras respostas.

Antes de tudo, acho que o hiato de representação entre problemas e soluções pode estar mais na mente do programador, de acordo com a sua formação e com os conceitos com os quais eles estão mais familiarizados.

OOP e FP analisam dados e operações de duas perspectivas diferentes e fornecem compensações diferentes, como Robert Harvey já apontou.

Um aspecto importante em que diferem é a maneira como permitem estender seu software.

Considere a situação em que você tem uma coleção de tipos de dados e uma coleção de operações; por exemplo, você tem diferentes formatos de imagem e mantém uma biblioteca de algoritmos para processar imagens.

A programação funcional facilita a adição de novas operações ao seu software: você só precisa de uma alteração local no seu código, ou seja, você adiciona uma nova função, que lida com diferentes formatos de dados de entrada. Por outro lado, a adição de novos formatos está mais envolvida: você precisa alterar todas as funções que já implementou (alteração não local).

A abordagem orientada a objetos é simétrica a isso: cada tipo de dados carrega sua própria implementação de todas as operações e é responsável por escolher a implementação correta em tempo de execução (envio dinâmico). Isso facilita a adição de um novo tipo de dados (por exemplo, um novo formato de imagem): você apenas adiciona uma nova classe e implementa todos os seus métodos. Por outro lado, adicionar uma nova operação significa alterar todas as classes que precisam fornecer essa operação. Em muitos idiomas, isso é feito estendendo uma interface e adaptando todas as classes que a implementam.

Essa abordagem diferente da extensão é um dos motivos pelos quais o OOP é mais apropriado para certos problemas em que o conjunto de operações varia com menos frequência do que o conjunto de tipos de dados nos quais essas operações funcionam. Um exemplo típico são GUIs: você tem um conjunto fixo de operações que todos os widgets deve implementar ( paint, resize, movee assim por diante) e uma coleção de widgets que você deseja estender.

Portanto, de acordo com essa dimensão, OOP e FP são apenas duas maneiras especulares de organizar seu código. Consulte o SICP , em particular a Seção 2.4.3, Tabela 2.22, e o parágrafo Passagem de mensagem .

Resumindo: no OOP, você usa dados para organizar operações, no FP, você usa operações para organizar os dados. Cada abordagem é mais forte ou mais fraca de acordo com o contexto. Em geral, nenhum dos dois apresenta uma lacuna representacional maior entre problema e solução.

Giorgio
fonte
1
Na verdade, o Padrão do Visitante (no OOP) fornece o mesmo poder que você disse para o FP. Ele permite que você adicione novas operações, dificultando a adição de novas classes. Gostaria de saber se você pode fazer o mesmo no FP (por exemplo, adicionando novos formatos em vez de operações).
Euphoric
1
O cenário de processamento de imagem não parece o melhor exemplo. Certamente você converteria as imagens em algum formato e processo interno que, em vez de escrever implementações separadas de todo o material de processamento de imagens para cada tipo de imagem?
Ei
1
@Giorgio talvez não esteja obtendo o significado pretendido desta parte: "adicionar novos formatos está mais envolvido: você precisa alterar todas as funções que já implementou".
Ei
2
@ Hey Giorgio provavelmente está se referindo ao chamado Problema da Expressão . "Adicionando novos formatos" significa "adicionando novos construtores (também conhecidos como 'casos') a um tipo de dados".
28515 Andres F.
1
@Euphoric: Eu não olhei para os detalhes, mas a contrapartida do FP no padrão de visitantes deve envolver uma Othervariante / construtor no seu tipo de dados e um parâmetro de função extra a ser passado para todas as funções para lidar com o outro caso. Obviamente, é estranho / menos natural em relação à solução OOP (envio dinâmico). Da mesma forma, o padrão de visitante é estranho / menos natural que a solução FP (uma função de ordem superior).
Giorgio
5

A maioria das linguagens funcionais não é orientada a objetos. Isso não significa que eles não têm objetos (no sentido de tipos complexos que possuem funcionalidades específicas associadas a eles). Haskell, como java, tem listas, mapas, matrizes, todos os tipos de árvores e muitos outros tipos complexos. Se você observar o módulo Haskell List ou Map, verá um conjunto de funções muito semelhantes aos métodos na maioria dos módulos equivalentes da biblioteca da linguagem OO. Se você inspecionar o código, encontrará até um encapsulamento semelhante, com alguns tipos (ou seus construtores, para ser mais preciso) e funções que podem ser utilizadas apenas por outras funções no módulo.

A maneira como você trabalha com esses tipos no Haskell geralmente não é diferente da maneira OO. Em Haskell eu digo

  null xs
  length xs

e em Java você diz

  xs.isEmpty
  xs.length

Tomate, tomate. As funções Haskell não estão vinculadas ao objeto, mas estão intimamente associadas ao seu tipo. "Ah, mas" , você diz, "em Java está chamando qual método de comprimento é apropriado para a classe real desse objeto". Surpresa - Haskell também faz polimorfismo com classes de tipos (e outras coisas).

Em Haskell, se eu tiver é - uma coleção de números inteiros - não importa se a coleção é uma lista ou conjunto ou matriz, esse código

  fmap (* 2) is

retornará uma coleção com todos os elementos dobrados. Polimorfismo significa que a função de mapa apropriada para o tipo específico será chamada.

Esses exemplos, na verdade, não são tipos realmente complexos, mas o mesmo se aplica a problemas mais difíceis. A ideia de que linguagens funcionais não permitem modelar objetos complexos e associar funcionalidades específicas a eles é simplesmente errada.

Não são diferenças importantes e significativas entre o estilo funcional e OO, mas eu não acho que esta resposta tem de lidar com eles. Você perguntou se as linguagens funcionais impedem (ou dificultam) a modelagem intuitiva de problemas e tarefas. A resposta é não.

itsbruce
fonte
Por uma questão de fato, você pode usar classes de tipo em Java / C #; você apenas passa explicitamente o dicionário de funções, em vez de o compilador inferir o correto com base no tipo.
Doval
Ah, definitivamente. Como William Cook disse, muitos códigos OO realmente fazem uso mais frequente de funções de ordem superior do que o código funcional, mesmo que o codificador provavelmente não esteja ciente disso.
precisa saber é
2
Você está fazendo uma falsa distinção. Uma lista não é mais uma estrutura de dados inerte do que uma pilha ou fila ou um simulador de jogo da velha. Uma lista pode conter qualquer coisa (em Haskell, pode muito bem ser funções parcialmente aplicadas) e define como essas coisas podem ser interagidas. Você poderia aplicar uma lista cheia de funções parcialmente aplicadas a outra lista de valores e o resultado seria uma nova lista contendo todas as combinações possíveis de funções da primeira e de entrada da segunda. Isso é muito mais que uma estrutura C.
precisa saber é
3
Os tipos são usados ​​para coisas mais variadas em linguagens funcionais do que as imperativas / OO (os sistemas de tipos tendem a ser mais poderosos e consistentes, por um lado). Os tipos e suas funções são usados ​​para modelar os caminhos de código (é por isso que várias linguagens funcionais simplesmente não possuem palavras-chave para loops - não são necessárias), por exemplo.
precisa saber é
4
@ Fuhrmanator "Não estou vendo como isso é feito no FP". Então você está reclamando de algo que não entende que não faz sentido; vá aprendê-lo, entendê-lo completamente, e então fará sentido. Talvez depois que faça sentido, você decida que é uma porcaria e não precise de outras pessoas para provar isso para você, embora outras pessoas como a acima a compreendam e não cheguem a essa conclusão. Você parece ter levado uma faca para um tiroteio e agora está dizendo a todos que as armas são inúteis porque não são afiadas.
Jimmy Hoffa
4

O FP realmente se esforça para reduzir o hiato representacional:

Algo que você verá muito nas linguagens funcionais é a prática de construir a linguagem (usando o design de baixo para cima) em uma Linguagem Específica de Domínio Incorporado (EDSL) . Isso permite que você desenvolva um meio de expressar suas preocupações comerciais de uma maneira natural para o seu domínio na linguagem de programação. Haskell e Lisp se orgulham disso.

Parte (se não todos) do que permite essa capacidade é mais flexibilidade e expressividade dentro do (s) idioma (s) de base; com funções de primeira classe, funções de ordem superior, composição de funções e, em alguns idiomas, tipos de dados algébricos (uniões discriminadas por AKA) e a capacidade de definir operadores *, há mais flexibilidade disponível para expressar as coisas do que com o OOP, que significa que você provavelmente encontrará maneiras mais naturais de expressar coisas do domínio do seu problema. (Deve-se dizer algo que muitas linguagens de POO adotaram muitos desses recursos recentemente, se não começando com eles.)

* Sim, em muitos idiomas OOP, você pode substituir os operadores padrão, mas em Haskell, você pode definir novos!

Na minha experiência trabalhando com linguagens funcionais (principalmente F # e Haskell, alguns Clojure e um pouco de Lisp e Erlang), tenho mais facilidade em mapear o espaço do problema para a linguagem do que com o OOP - especialmente com tipos de dados algébricos, que eu acho mais flexível que as aulas. Algo que me impressionou ao começar com o FP, principalmente com Haskell, foi que eu tinha que pensar / trabalhar em um nível um pouco mais alto do que costumava em linguagens imperativas ou OOP; você pode estar se deparando com isso também.

Paulo
fonte
As preocupações comerciais (do cliente) não são expressas com muita frequência em funções de ordem superior. Mas um cliente pode escrever uma história de usuário de uma linha e fornecer regras de negócios (ou você pode tirá-las do cliente). Estou interessado na modelagem de domínio (de cima para baixo?) (Desses artefatos) que nos permite chegar a abstrações do problema que são mapeadas para funções de primeira classe etc. Você pode citar algumas referências? Você pode usar um exemplo concreto de um domínio, abstrações etc.?
Fuhrmanator
3
@ Fuhrmanator Um cliente ainda pode escrever histórias de usuário de uma linha e regras de negócios, independentemente de você usar OOP e FP . Não espero que os clientes entendam funções de ordem superior, assim como não entendo herança, composição ou interfaces.
Andres F.
1
@ Fuhrmanator Com que frequência o cliente expressou suas preocupações em termos de genéricos Java ou classes e interfaces básicas abstratas? Querido Deus. Paul deu uma resposta muito boa, explicando um método prático e confiável de modelagem usando técnicas que certamente não são difíceis de visualizar. E, no entanto, você insiste que seja descrito em termos de uma técnica de modelagem específica para um paradigma em particular, como se essa fosse, de alguma forma, a maneira mais natural de representar o design e qualquer outra coisa possa ser redesenhada em seus termos.
precisa saber é
@ Fuhrmanator Isso pode não ser tão alto quanto você está procurando, mas deve fornecer algumas dicas sobre o processo de design usando técnicas funcionais: Designing With Types . Eu recomendo navegar nesse site em geral porque ele tem alguns artigos excelentes.
paul
@Fuhrmanator Há também esta série Thinking Functionally
Paul
3

Como Niklaus Wirth colocou, "Algoritmos + Estruturas de Dados = Programas". A programação funcional é sobre a maneira de organizar algoritmos e não diz muito sobre maneiras de organizar estruturas de dados. De fato, existem linguagens FP tanto com variáveis ​​mutáveis ​​(Lisp) quanto imutáveis ​​(Haskell, Erlang). Se você deseja comparar e contrastar FP com alguma coisa, deve escolher a programação imperativa (C, Java) e declarativa (Prolog).

OOP é, por outro lado, uma maneira de construir estruturas de dados e anexar algoritmos a elas. O FP não impede que você construa estruturas de dados semelhantes às do OOP. Se você não acredita em mim, dê uma olhada nas declarações do tipo Haskell. No entanto, a maioria das linguagens FP concorda que as funções não pertencem às estruturas de dados e devem estar no mesmo espaço para nome. Isso é feito para simplificar a criação de novos algoritmos via composição de funções. De fato, se você sabe qual entrada uma função recebe e qual saída ela produz, por que deveria importar qual estrutura de dados pertence? Por exemplo, por que a addfunção precisa ser chamada em uma instância do tipo Inteiro e transmitida um argumento em vez de simplesmente ser transmitida por dois argumentos Inteiros?

Portanto, não vejo por que o FP deva tornar as soluções mais difíceis de entender em geral, e acho que não o faz de qualquer maneira. No entanto, lembre-se de que um programador imperativo experiente certamente encontrará programas funcionais mais difíceis de entender do que os imperativos e vice-versa. Isso é semelhante à dicotomia Windows - Linux, quando as pessoas que investiram 10 anos em se sentirem confortáveis ​​com o ambiente Windows consideram o Linux difícil após um mês de uso, e aqueles que estão acostumados ao Linux não conseguem a mesma produtividade no Windows. Portanto, a "lacuna representacional" de que você está falando é muito subjetiva.

mkalkov
fonte
Por causa do encapsulamento e ocultação de dados, que não são princípios de OO em si, não concordo inteiramente com o OO sendo estruturas de dados + algoritmos (essa é apenas a visão interna). A beleza de qualquer boa abstração é que há algum serviço que ele fornece para resolver parte do problema, sem que você precise entender muitos detalhes. Eu acho que você está falando de encapsulamento quando separa funções e dados no FP, mas sou muito verde para ter certeza. Além disso, editei minha pergunta para me referir ao rastreamento da solução até o problema (para esclarecer o significado da lacuna representacional).
Fuhrmanator
if you know what input a function takes and what output it produces, why should it matter which data structure it belongs too?Isso parece muito com coesão, o que para qualquer sistema modular é importante. Eu argumentaria que não saber onde encontrar uma função tornaria mais difícil entender uma solução, o que se deve a uma maior lacuna representacional. Muitos sistemas OO têm esse problema, mas é por causa de um design ruim (baixa coesão). Novamente, a questão do espaço para nome está fora dos meus conhecimentos em FP, então talvez não seja tão ruim quanto parece.
Fuhrmanator
1
@Fuhrmanator Mas você não sabe onde encontrar uma função. E há apenas uma função, não várias funções com o mesmo nome, definidas para cada tipo de dados (novamente, consulte o "Problema de Expressão"). Por exemplo, para as funções da biblioteca Haskell (que você é encorajado a usar, em vez de redescobrir o volante ou criar versões ligeiramente menos úteis dessas funções), você tem ferramentas maravilhosas de descoberta, como o Hoogle , que é tão poderoso que permite pesquisar por assinatura (experimente! :))
Andres F.
1
@ Fuhrmanator, depois de "Isso parece muito com coesão", eu esperava que você concluísse logicamente que as linguagens FP permitem escrever programas com maior coesão, mas você me surpreendeu. :-) Eu acho que você deve escolher um idioma FP, aprendê-lo e decidir por si próprio. Se eu fosse você, sugiro começar com Haskell, pois é bastante puro e, portanto, não permitirá que você escreva código em estilo imperativo. Erlang e alguns Lisp também são boas escolhas, mas se misturam em outros estilos de programação. Scala e Clojure, IMO, são bastante complicados para começar.
Mkalkov