Por que a programação funcional ainda não assumiu?

197

Eu li alguns textos sobre programação declarativa / funcional (linguagens), experimentei Haskell e também escrevi um. Pelo que vi, a programação funcional tem várias vantagens sobre o estilo imperativo clássico:

  • Programas sem estado; Sem efeitos colaterais
  • Concorrência; Joga extremamente bem com a crescente tecnologia multi-core
  • Os programas geralmente são mais curtos e, em alguns casos, mais fáceis de ler
  • A produtividade aumenta (exemplo: Erlang)

  • A programação imperativa é um paradigma muito antigo (tanto quanto eu sei) e possivelmente não é adequado para o século XXI

Por que as empresas que usam ou programas escritos em linguagens funcionais ainda são "raras"?

Por que, quando analisamos as vantagens da programação funcional, ainda estamos usando linguagens de programação imperativas?

Talvez fosse muito cedo para isso em 1990, mas hoje?

pankrax
fonte
1
NOTA: esta questão foi discutida na meta pelo menos duas vezes, e o consenso é que ela deve ser mantida, embora arquivada através do bloqueio de "significado histórico" mencionado acima. Encorajo vivamente qualquer pessoa que esteja vendo isso com o objetivo de desbloqueá-lo a parar e agradecer por não ter participado de mais uma discussão tediosa sobre essa pergunta, aproveite as respostas como elas são e prossiga com seus negócios.
29416 Shog9

Respostas:

530

Porque todas essas vantagens também são desvantagens.

Programas sem estado; Sem efeitos colaterais

Programas do mundo real são sobre efeitos colaterais e mutações. Quando o usuário pressiona um botão, é porque ele quer que algo aconteça. Quando digitam algo, querem que esse estado substitua o estado que costumava estar lá. Quando Jane Smith, na contabilidade, se casa e muda seu nome para Jane Jones, é melhor o banco de dados que apóia o processo de negócios que imprime sua folha de pagamento trata de lidar com esse tipo de mutação. Quando você dispara a metralhadora contra o alienígena, a maioria das pessoas não o modela mentalmente como a construção de um novo alienígena com menos pontos de vida; eles modelam isso como uma mutação das propriedades de um alienígena existente.

Quando os conceitos da linguagem de programação funcionam fundamentalmente contra o domínio que está sendo modelado, é difícil justificar o uso dessa linguagem.

Concorrência; Joga extremamente bem com a crescente tecnologia multi-core

O problema é apenas empurrado. Com estruturas de dados imutáveis, você tem segurança de encadeamento barata, ao custo de possivelmente trabalhar com dados obsoletos. Com estruturas de dados mutáveis, você tem o benefício de sempre trabalhar em dados novos, ao custo de ter que escrever uma lógica complicada para manter os dados consistentes. Não é como se um deles fosse obviamente melhor que o outro.

Os programas geralmente são mais curtos e, em alguns casos, mais fáceis de ler

Exceto nos casos em que são mais longos e difíceis de ler. Aprender a ler programas escritos em um estilo funcional é uma habilidade difícil; as pessoas parecem muito melhores em conceber os programas como uma série de etapas a serem seguidas, como uma receita, e não como uma série de cálculos a serem realizados.

A produtividade aumenta (exemplo: Erlang)

A produtividade precisa aumentar muito para justificar as enormes despesas de contratação de programadores que sabem como programar em um estilo funcional.

E lembre-se, você não quer jogar fora um sistema em funcionamento; a maioria dos programadores não está construindo novos sistemas a partir do zero, mas mantendo sistemas existentes, a maioria dos quais foi construída em linguagens não funcionais. Imagine tentar justificar isso para os acionistas. Por que você descartou seu sistema de folha de pagamento em funcionamento existente para criar um novo com o custo de milhões de dólares? "Porque a programação funcional é impressionante" é improvável que encante os acionistas.

A programação imperativa é um paradigma muito antigo (tanto quanto eu sei) e possivelmente não é adequado para o século XXI

A programação funcional também é muito antiga. Não vejo como a idade do conceito é relevante.

Não me interpretem mal. Adoro programação funcional, entrei para essa equipe porque queria ajudar a trazer conceitos da programação funcional para o C # e acho que a programação em um estilo imutável é o caminho do futuro. Mas existem enormes custos para a programação em um estilo funcional que não pode simplesmente ser desperdiçado. A mudança para um estilo mais funcional acontecerá lenta e gradualmente ao longo de décadas. E é isso que será: uma mudança para um estilo mais funcional, não um abraço generalizado da pureza e beleza de Haskell e o abandono do C ++.

Eu construo compiladores para ganhar a vida e definitivamente estamos adotando um estilo funcional para a próxima geração de ferramentas de compilador. Isso porque a programação funcional é fundamentalmente uma boa combinação para os tipos de problemas que enfrentamos. Nossos problemas consistem em coletar informações brutas - strings e metadados - e transformá-las em strings e metadados diferentes. Nas situações em que ocorrem mutações, como se alguém estivesse digitando no IDE, o espaço do problema se presta inerentemente a técnicas funcionais, como a reconstrução incremental de apenas as partes da árvore que foram alteradas. Muitos domínios não possuem essas boas propriedades que os tornam obviamente acessíveis a um estilo funcional .

Eric Lippert
fonte
41
"Quando Jane Smith, na contabilidade, se casa e muda seu nome para Jane Jones, é melhor o banco de dados que apóia o processo de negócios que imprime seu cheque de pagamento lidar com esse tipo de mutação". Haverá um registro do antigo nome de Jane Smith, não atualizamos retroativamente todas as instâncias do antigo nome de Jane para seu novo nome;)
Juliet
40
@ Juliet: Claro. O que quero dizer é que, se você tem um objeto que representa um funcionário, faz sentido pensar na operação "alterar o nome do funcionário" como uma mutação do objeto que representa o funcionário que não altera a identidade do objeto . Quando Jane Smith muda seu nome, você não cria uma funcionária diferente chamada Jane Jones que, de outra forma, é a mesma. Não há dois funcionários com dois nomes diferentes. É natural modelar esse processo como uma mutação de um objeto, não como a construção de um novo objeto.
Eric Lippert
24
Essa é uma boa resposta, mas acho que você exagera seu caso às vezes. Como Juliet disse, embora as pessoas possam pensar nisso como uma mudança de nome, é realmente uma substituição de nome em um nível mais profundo. E embora os programas funcionais possam ser mais difíceis para as pessoas lerem (porque é uma habilidade aprendida), isso geralmente não é porque são mais longos. Um programa Haskell quase sempre será mais conciso do que, digamos, um programa Java - mesmo em um domínio de "mau ajuste" com muito estado inerente.
Chuck
29
+1 Foi uma lufada de ar fresco ler esta resposta. Fantástico ouvir esse pragmatismo (com uma paixão subjacente pela programação funcional) de alguém em sua posição.
Escape
11
"Como todas essas vantagens também são desvantagens. Programas sem estado; sem efeitos colaterais": Pelo que entendi (não sei o suficiente sobre o FP para escrever uma resposta autorizada), isso não está correto . A programação funcional é sobre transparência referencial e não para evitar o estado (mesmo que o estado deva ser tratado adequadamente para garantir a transparência referencial). Haskell permite estado e mutação. Ele apenas fornece ferramentas diferentes (alguém poderia argumentar, melhor) para raciocinar sobre isso.
Giorgio
38

Masterminds of Programming: Conversas com os criadores das principais linguagens de programação

[Haskell]

Por que você acha que nenhuma linguagem de programação funcional entrou no mainstream?

John Hughes: Marketing ruim! Não quero dizer propaganda; já tivemos bastante disso. Refiro-me a uma escolha cuidadosa de um nicho de mercado alvo a ser dominado, seguido de um esforço determinado para tornar a programação funcional de longe a maneira mais eficaz de abordar esse nicho. Nos dias felizes dos anos 80, pensávamos que a programação funcional era boa para tudo - mas chamar a nova tecnologia de "boa para tudo" é o mesmo que chamá-la de "particularmente boa em nada". Qual é a marca que deveria ser? Esse é um problema que John Launchbury descreveu muito claramente em sua palestra convidada no ICFP. A Galois Connections quase fracassou quando sua marca era "software em linguagens funcionais", mas eles foram fortalecendo desde que se concentraram no "software de alta garantia".

Muitas pessoas não têm idéia de como a inovação tecnológica acontece, e esperam que uma melhor tecnologia simplesmente se torne dominante por si só (o efeito "melhor ratoeira" ), mas o mundo simplesmente não é assim.

Nick Dandoulakis
fonte
36
Haskell: depois de 20 anos, um sucesso da noite para o dia!
Julieta
siga o link e leia as resenhas para uma descrição bastante divertida de Grady Booch. Não faço ideia de quem é Booch, mas isso me fez rir de qualquer maneira.
Fearofawhackplanet
4
Grady Booch é responsável, em última instância, juntamente com Jacobson e Rumbaugh, pela abominação que é a UML.
APENAS MINHA OPINIÃO correta
27

A resposta das ações é que nenhuma delas substituirá ou substituirá a outra - elas são ferramentas diferentes, com diferentes conjuntos de prós e contras, e cuja abordagem tem vantagens diferirá dependendo do projeto e de outros problemas "leves", como o conjunto de talentos disponíveis.

Acho que você está certo de que o crescimento da simultaneidade devido ao multi-core aumentará a porcentagem (do conjunto global de projetos de desenvolvimento) quando a programação funcional é escolhida em detrimento de outros estilos.

Acho que hoje é raro, porque a maioria dos talentos profissionais atuais se sente mais à vontade com tecnologias imperativas e orientadas a objetos. Por exemplo, mais de uma vez escolhi o Java como a linguagem para um projeto comercial porque era bom o suficiente, não controverso, e sei que nunca ficarei sem pessoas que possam programar (bem o suficiente) nele.

G__
fonte
Isso é muito perspicaz e deliciosamente pragmático. Definitivamente, a melhor resposta que já vi para essa pergunta em todas as suas formas.
Benson
Talvez por um idioma em que ambos sejam cidadãos de primeira classe se torne popular.
Kevin Kostlan
1
Concordo 110%. Em várias ocasiões, tentei entrar no FP, mas perdi a vontade de continuar depois de algumas semanas. Venho programando proceduralmente por mais de 30 anos e estou muito acostumado a imperativos. Isso vale para o setor de TI em geral. A mudança não será fácil nem rápida.
Richard Eng
26

Apesar das vantagens da programação funcional, a programação imperativa e orientada a objetos nunca desaparece completamente.

A programação imperativa e orientada a objetos é uma descrição passo a passo do problema e de sua solução. Como tal, pode ser mais fácil de entender. A programação funcional pode ser um pouco obscura.

Por fim, um programa útil sempre terá efeitos colaterais (como fornecer saída real ao usuário para consumo); portanto, a mais pura das linguagens funcionais ainda precisará de uma maneira de entrar no mundo imperativo de tempos em tempos.

O estado da arte atual é que linguagens imperativas (como C #) tomam emprestado recursos do mundo funcional (como instruções lambda) e vice-versa.

Robert Harvey
fonte
3
OOP não é algum tipo de subconjunto de programação imperativa?
Pankrax
9
OOP é um superconjunto. OOP é imperativo como C ++ é a C.
Robert Harvey
10
Eu não acho que OOP é necessariamente dependente de programação imperativa. Procure um Clojure ou CLOS - ambos são funcionais, mas orientados a objetos.
Gabe
9
As linguagens OO tendem a ser imperativas, mas não precisam ser. OCaml é uma linguagem funcional (embora não puramente) funcional, cuja razão de ser inteira é OO.
Chuck
7
Não estou entendendo por que OOP é um superconjunto de programação imperativa. Nem todo código imperativo é OOP e nem todo código funcional é não OOP. Eu prefiro dizer que OOP é a programação imperativa e a programação funcional, como asas aerodinâmicas, é para carros de corrida, aviões, foguetes, ventiladores de refrigeração ou moinhos de vento, ou ... ou seja, os conceitos estão relacionados, mas não estão intimamente ligados uma conexão 1 para 1.
Sebastian Mach
21

Não é?

O Smalltalk era um ótimo sistema orientado a objetos na época. Por que a programação orientada a objetos não assumiu? Bem, tem. Simplesmente não se parece com Smalltalk. As linguagens mainstream continuam ficando mais parecidas com Smalltalk com C ++, Java, C # etc. A moda e o estilo mudam mais devagar do que qualquer coisa; portanto, quando o OO se tornou mainstream, conseguimos obtê-lo colando partes do OO em idiomas antigos, para que parecesse o suficiente para C engolir .

Funcional é da mesma maneira. Haskell era uma ótima linguagem funcional. Mas temos ainda mais massa de programadores tradicionais usando sintaxe do tipo C hoje do que há 20 anos. Portanto, ele deve se parecer com C. Concluído: observe qualquer expressão LINQ e me diga que não é funcional.

Ken
fonte
2
Ponto interessante, mas como as línguas tradicionais estão ficando mais parecidas com Smalltalk? C ++, Java e C #, por exemplo, não se baseiam no envio de mensagens, que (acredito) é a parte mais importante do paradigma Smalltalk.
Jonathan Sterling
4
Jonathan: Escolha qualquer recurso Smalltalk e observe como ele é mais fraco em C ++ (o mais antigo), OK em Java e melhor em C #. Por exemplo, GC (somente Java / C #), autobox (posteriormente, somente Java / C #), fechamentos (somente C #) e reflexão (presente em Java, melhor em C #). Se você deseja passar mensagens, veja C # 4 dynamic. Esse é o mais Smalltalk-y desses recursos, então não é surpresa para mim que ele esteja presente apenas na versão mais recente do mais moderno desses três idiomas. :-)
Ken
Javascript, Python e Ruby são bons exemplos de como ele realmente tem
nafg
15

Acredito que linguagens imperativas são mais predominantes simplesmente porque é a isso que mais pessoas estão acostumadas. Nem a programação funcional nem o modelo de programação imperativa são mais obscuros ou acadêmicos do que o outro. De fato, são complementos.

Um pôster dizia que o código imperativo é mais fácil de entender do que o código de programação funcional. Isso só é verdade se o leitor já tiver visto código imperativo, especialmente se os exemplos anteriores fizerem parte da mesma "família" (por exemplo, C / C ++, Perl, PHP e Java). Eu não diria que isso é verdade para qualquer linguagem imperativa; faça uma comparação entre Java e Forth, para dar um exemplo extremo.

Para um leigo, todas as linguagens de programação são bobagens indecifráveis, exceto talvez as linguagens detalhadas, como Hypertalk e SQL. (De notar, o SQL é uma linguagem declarativa e / ou funcional e goza de enorme popularidade.)

Se tivéssemos sido treinados inicialmente em uma linguagem Lisp-y ou Haskell-y desde o início, todos pensaríamos que as linguagens de programação funcional são perfeitamente normais.

Barry Brown
fonte
"Um pôster dizia que o código imperativo é mais fácil de entender do que o código de programação funcional. Isso só é verdade se o leitor já tiver visto o código imperativo, especialmente se os exemplos anteriores fizerem parte da mesma" família "(por exemplo, C / C ++, Perl, PHP e Java). ": Muito verdadeiro (+1): Lembro-me de quanto esforço tive para colocar em aprender Pascal e C quando comecei a programar. E como é fácil ler Scala, Haskell ou Scheme agora que tenho alguma experiência com esses idiomas.
Giorgio
2
A única razão pela qual ainda considero útil o estado mutável às vezes é que ele oferece uma maneira fácil de escrever código rápido (sem cópia); mas a razão para isso pode ser que eu não conheço programação funcional suficiente e que, para 90% das situações, você possa escrever código funcional rápido sem usar estado mutável.
Giorgio
3
Um dos ambientes mais utilizados e de longa duração para organizar a computação é a planilha; essencialmente um ambiente de programação funcional com células em vez de variáveis ​​nomeadas. Não acredito que as pessoas, em geral, concebam inerentemente os programas como uma série de etapas. Programadores impregnados de linguagens imperativas generalizadas, talvez.
Jpnp
14

Você já obteve respostas suficientes para mencionar apenas algumas coisas que ainda não vi mencionadas.

Primeiro e (em minha opinião), as linguagens processuais se beneficiaram muito de seu grau de comunalidade. Por exemplo, quase todo mundo que conhece quase todas as linguagens processuais (OO) convencionais em quase qualquer grau pode ler a maioria das outras razoavelmente bem. Eu evito trabalhar ativamente em Java, C #, Cobol, Fortran ou Basic (por apenas alguns exemplos), mas consigo ler qualquer um deles razoavelmente bem - quase tão bem, na verdade, quanto as pessoas que os usam todos os dias.

No lado funcional, isso é muito menos verdadeiro. Apenas por exemplo, também posso escrever Scheme de maneira bastante razoável, mas isso é de pouca utilidade na leitura de Ocaml ou Haskell (por apenas alguns exemplos). Mesmo dentro de uma única família (por exemplo, Scheme vs., Common Lisp), a familiaridade com uma parece não se traduzir tão bem na outra.

A afirmação de que o código funcional é mais legível tende a ser verdadeira apenas sob uma faixa estreita de condições. Para pessoas que estão extremamente familiarizadas com o idioma, a legibilidade é realmente excelente - mas para todos os outros, geralmente é quase inexistente. Pior, enquanto as diferenças nas linguagens procedurais são amplamente de sintaxe e, portanto, relativamente fáceis de aprender, as diferenças nas linguagens funcionais são muitas vezes muito mais fundamentais, portanto, requerem um estudo considerável para realmente entender (por exemplo, saber que o Lisp é de pouca ajuda na compreensão das mônadas).

O outro ponto importante é que a idéia de que os programas funcionais são mais curtos que os processuais geralmente se baseia mais na sintaxe do que na semântica. Os programas escritos em Haskell (por exemplo) são frequentemente bastante curtos, mas seu funcionamento é uma parte bastante pequena disso. Muita coisa, se é que Haskell tem uma sintaxe relativamente concisa.

Poucas linguagens puramente funcionais podem competir bem com o APL pelo código fonte conciso (embora, para ser justo, o APL também suporte a criação de funções de nível superior, portanto, essa não é uma diferença muito grande, como em outros casos). Por outro lado, Ada e C ++ (apenas para alguns exemplos) podem ser bastante competitivos em termos de número de operações necessárias para realizar uma determinada tarefa, mas a sintaxe é (pelo menos geralmente) substancialmente mais detalhada.

Jerry Coffin
fonte
Excelente comentário! Eu concordo plenamente. Acho a maioria das linguagens processuais bastante fáceis de ler e entender, mesmo sendo apenas um especialista genuíno em algumas delas. Não posso dizer o mesmo sobre idiomas FP.
Richard Eng
1
Outro ponto importante é que, em qualquer paradigma, você encontra diversos conhecimentos, de iniciantes a gurus. O código FP pode ser facilmente legível e compreensível para os especialistas, mas os programadores medíocres ainda podem ter dificuldades. Os especialistas geralmente compreendem uma fração muito pequena da comunidade de PF.
Richard Eng
11

Nenhuma necessidade percebida

Lembro-me da resposta do meu antigo chefe Rick Cline quando lhe mostrei uma cópia da palestra do John Backus 'Turing Award, intitulada Pode-se libertar a programação do estilo von Neumann?

Sua resposta: "Talvez alguns de nós não desejem se libertar do estilo von Neumann!"

Mark Harrison
fonte
10

Por que a programação funcional ainda não assumiu?

Funcional é melhor para algumas coisas e pior para outras, para que nunca "assuma o controle". Já é onipresente no mundo real.

Programas sem estado; Sem efeitos colaterais

Programas sem estado são mais fáceis de testar. Agora isso é amplamente apreciado e frequentemente explorado na indústria.

Concorrência; Joga extremamente bem com a crescente tecnologia multi-core Os programas geralmente são mais curtos e, em alguns casos, mais fáceis de ler A produtividade aumenta (exemplo: Erlang)

Você está confluindo concorrente e paralelismo.

A simultaneidade pode ser feita efetivamente usando processos sequenciais de comunicação (CSP). O código dentro de um CSP pode alterar seu estado local, mas as mensagens enviadas entre eles sempre devem ser imutáveis.

A programação puramente funcional é extremamente ruim com o multicore porque é muito hostil ao cache. Os núcleos acabam competindo pela memória compartilhada e os programas paralelos não são redimensionados.

Por que as empresas que usam ou programas escritos em linguagens funcionais ainda são "raras"?

O Scala é frequentemente considerado como uma linguagem funcional, mas não é mais funcional que o C #, que é uma das línguas mais populares do mundo atualmente.

Por que, quando analisamos as vantagens da programação funcional, ainda estamos usando linguagens de programação imperativas?

A programação puramente funcional tem muitas desvantagens sérias, por isso usamos linguagens funcionais impuras como Lisp, Scheme, SML, OCaml, Scala e C #.

Jon Harrop
fonte
7

Quando penso no que a programação funcional pode trazer para meus projetos no trabalho, sempre sou conduzida pelo mesmo caminho:

  1. Para obter todas as vantagens da programação funcional, você precisa de preguiça. Sim, existem linguagens funcionais estritas, mas os benefícios reais da programação funcional não brilha tão bem no código estrito. Por exemplo, em Haskell, é fácil criar uma sequência de operações preguiçosas em uma lista e concatená-las e aplicá-las a uma lista. Por exemplo. op1 $ op2 $ op3 $ op4 $ someList. Eu sei que não vai construir a lista inteira e, internamente, só vou obter um loop agradável que percorre os elementos um de cada vez. Isso permite que você escreva um código realmente modular. A interface entre dois módulos pode envolver a entrega de estruturas de dados potencialmente vastas e, no entanto, você não precisa ter a estrutura residente.

  2. Mas quando você tem preguiça, fica difícil argumentar sobre o uso da memória. Alterar os sinalizadores do compilador Haskell frequentemente altera a quantidade de memória usada por um algoritmo de O (N) para O (1), exceto que às vezes não. Isso não é realmente aceitável quando você tem aplicativos que precisam aproveitar ao máximo toda a memória disponível e não é ótimo, mesmo para aplicativos que não precisam de toda a memória.

sigfpe
fonte
A preguiça também interage menos do que o ideal com a depuração.
18710 Brian
3
Como eu acho que muitos dos erros que eu persigo em outros idiomas estão relacionados à falta de transparência referencial, estou menos preocupado com os problemas de depuração, mesmo que às vezes possam ser uma dor.
Sigfpe 15/05
6

Duas coisas:

  1. Leva tempo, não importa quão boa seja a tecnologia. As idéias por trás da FP têm cerca de 70 anos. Mas seu uso principal em engenharia de software (nas trincheiras, na indústria) é provavelmente inferior a 10 anos. É possível pedir que os desenvolvedores adotem mentalidades racialmente novas, mas isso leva tempo (muitos, muitos anos). Por exemplo, o POO realmente ganhou uso mainstream no início dos anos 80. No entanto, não obteve dormência até o final dos anos 90.
  2. Você precisa que as pessoas sejam forçadas a enfrentar a força de uma tecnologia antes que ela atinja seu tamanho . Atualmente, as pessoas estão usando ferramentas que não fazem uso do paralelismo e as coisas funcionam bem. Quando aplicativos que não usam paralelismo se tornam insuportavelmente lentos; então muitas pessoas serão forçadas a usar ferramentas de paralelismo e a FP poderá aumentar em popularidade. Isso também pode se aplicar aos outros pontos fortes da FP.
Phil
fonte
3
O FP é muito bom na reutilização de código. Provavelmente melhor que OO. Eu tive que lidar com isso no trabalho algumas vezes, migrando para tipos diferentes, e um novo sistema e era indolor.
Nlucaroni
@Freddy Rios e @nlucaroni. Eu reformulei o comentário para esclarecer uma interpretação incorreta.
Phil