Estou realmente tendo dificuldade em entender a diferença entre os paradigmas de programação procedural e funcional .
Aqui estão os dois primeiros parágrafos da entrada da Wikipedia sobre programação funcional :
Na ciência da computação, a programação funcional é um paradigma de programação que trata a computação como a avaliação de funções matemáticas e evita estados e dados mutáveis. Ele enfatiza a aplicação de funções, em contraste com o estilo de programação imperativo, que enfatiza as mudanças no estado. A programação funcional tem suas raízes no cálculo lambda, um sistema formal desenvolvido na década de 1930 para investigar a definição de função, sua aplicação e recursão. Muitas linguagens de programação funcional podem ser vistas como elaborações do cálculo lambda.
Na prática, a diferença entre uma função matemática e a noção de uma "função" usada na programação imperativa é que as funções imperativas podem ter efeitos colaterais, alterando o valor do estado do programa. Por isso, eles carecem de transparência referencial, ou seja, a mesma expressão de linguagem pode resultar em valores diferentes em momentos diferentes, dependendo do estado do programa em execução. Por outro lado, no código funcional, o valor de saída de uma função depende apenas dos argumentos de entrada para a função, portanto, chamar uma função
f
duas vezes com o mesmo valor para um argumentox
produzirá o mesmo resultadof(x)
ambas as vezes. A eliminação dos efeitos colaterais pode tornar muito mais fácil entender e prever o comportamento de um programa, o que é uma das principais motivações para o desenvolvimento da programação funcional.
No parágrafo 2, onde diz
Por outro lado, no código funcional, o valor de saída de uma função depende apenas dos argumentos de entrada para a função, portanto, chamar uma função
f
duas vezes com o mesmo valor para um argumentox
produzirá o mesmo resultado nasf(x)
duas vezes.
Não é exatamente o mesmo caso para programação procedural?
O que se deve procurar em procedural vs funcional que se destaque?
Respostas:
Programação Funcional
A programação funcional se refere à capacidade de tratar funções como valores.
Vamos considerar uma analogia com valores "regulares". Podemos pegar dois valores inteiros e combiná-los usando o
+
operador para obter um novo inteiro. Ou podemos multiplicar um inteiro por um número de ponto flutuante para obter um número de ponto flutuante.Na programação funcional, podemos combinar dois valores de função para produzir um novo valor de função usando operadores como compor ou elevador . Ou podemos combinar um valor de função e um valor de dados para produzir um novo valor de dados usando operadores como map ou fold .
Observe que muitas linguagens têm recursos de programação funcional - até mesmo linguagens que geralmente não são consideradas linguagens funcionais. Até mesmo o avô FORTRAN suportava valores de função, embora não oferecesse muito em termos de operadores de combinação de funções. Para uma linguagem ser chamada de "funcional", ela precisa abraçar amplamente os recursos de programação funcional.
Programação Processual
A programação procedural refere-se à capacidade de encapsular uma sequência comum de instruções em um procedimento, de forma que essas instruções possam ser chamadas de muitos lugares sem recorrer ao copiar e colar. Como os procedimentos foram um desenvolvimento muito inicial na programação, a capacidade está quase invariavelmente ligada ao estilo de programação exigido pela programação em linguagem de máquina ou assembly: um estilo que enfatiza a noção de locais de armazenamento e instruções que movem dados entre esses locais.
Contraste
Os dois estilos não são realmente opostos - eles são apenas diferentes um do outro. Existem linguagens que abraçam totalmente os dois estilos (LISP, por exemplo). O cenário a seguir pode dar uma ideia de algumas diferenças entre os dois estilos. Vamos escrever um código para um requisito sem sentido em que queremos determinar se todas as palavras em uma lista têm um número ímpar de caracteres. Primeiro, estilo de procedimento:
Vou considerar que este exemplo é compreensível. Agora, estilo funcional:
Trabalhando de dentro para fora, esta definição faz o seguinte:
compose(odd, length)
combina as funçõesodd
elength
para produzir uma nova função que determina se o comprimento de uma string é ímpar.map(..., words)
chama essa nova função para cada elemento emwords
, em última análise, retornando uma nova lista de valores booleanos, cada um indicando se a palavra correspondente tem um número ímpar de caracteres.apply(and, ...)
aplica o operador "e" à lista resultante e -ing todos os booleanos juntos para produzir o resultado final.Você pode ver a partir desses exemplos que a programação procedural está muito preocupada em mover valores nas variáveis e em descrever explicitamente as operações necessárias para produzir o resultado final. Em contraste, o estilo funcional enfatiza a combinação de funções necessárias para transformar a entrada inicial na saída final.
O exemplo também mostra os tamanhos relativos típicos de código procedural versus código funcional. Além disso, demonstra que as características de desempenho do código procedural podem ser mais fáceis de ver do que as do código funcional. Considere: as funções calculam os comprimentos de todas as palavras na lista ou cada uma para imediatamente após encontrar a primeira palavra de comprimento par? Por outro lado, o código funcional permite uma implementação de alta qualidade para realizar algumas otimizações bastante sérias, uma vez que expressa principalmente a intenção em vez de um algoritmo explícito.
Leitura Adicional
Essa dúvida surge muito ... veja, por exemplo:
A palestra do prêmio Turing de John Backus explica as motivações para a programação funcional em grandes detalhes:
A programação pode ser libertada do estilo de von Neumann?
Eu realmente não deveria mencionar esse artigo no presente contexto porque ele se torna muito técnico, muito rapidamente. Eu simplesmente não pude resistir porque acho que é verdadeiramente fundamental.
Adendo - 2013
Os comentaristas apontam que as linguagens contemporâneas populares oferecem outros estilos de programação além de procedimental e funcional. Essas linguagens geralmente oferecem um ou mais dos seguintes estilos de programação:
Veja os comentários abaixo para exemplos de como os exemplos de pseudocódigo nesta resposta podem se beneficiar de alguns dos recursos disponíveis desses outros estilos. Em particular, o exemplo de procedimento se beneficiará da aplicação de virtualmente qualquer construção de nível superior.
Os exemplos exibidos evitam deliberadamente a mistura desses outros estilos de programação para enfatizar a distinção entre os dois estilos em discussão.
fonte
odd_words(words)
definição faz algo diferente da respostaallOdd
. Para filtragem e mapeamento, as compreensões de lista são freqüentemente preferidas, mas aqui a funçãoallOdd
deve reduzir uma lista de palavras a um único valor booleano.A diferença real entre programação funcional e imperativa é a mentalidade - os programadores imperativos estão pensando em variáveis e blocos de memória, enquanto os programadores funcionais estão pensando: "Como posso transformar meus dados de entrada em dados de saída" - seu "programa" é o pipeline e um conjunto de transformações nos dados para levá-los da entrada para a saída. Essa é a parte interessante da IMO, não a parte "Não usarás variáveis".
Como consequência dessa mentalidade, os programas de PF geralmente descrevem o que vai acontecer, em vez do mecanismo específico de como isso vai acontecer - isso é poderoso porque se pudermos afirmar claramente o que significa "Selecionar" e "Onde" e "Agregar", nós estão livres para trocar suas implementações, assim como fazemos com AsParallel () e, de repente, nosso aplicativo de thread único é dimensionado para n núcleos.
fonte
Não, porque o código de procedimento pode ter efeitos colaterais. Por exemplo, ele pode armazenar o estado entre as chamadas.
Dito isso, é possível escrever código que satisfaça esta restrição em linguagens consideradas procedurais. E também é possível escrever código que quebre essa restrição em algumas linguagens consideradas funcionais.
fonte
Não concordo com a resposta de WReach. Vamos desconstruir um pouco sua resposta para ver de onde vem a discordância.
Primeiro, seu código:
e
A primeira coisa a notar é que ele está confundindo:
programação e sem a capacidade de programação de estilo iterativo para ter um fluxo de controle mais explícito do que um estilo funcional típico.
Vamos falar rapidamente sobre isso.
O estilo centrado na expressão é aquele em que as coisas, tanto quanto possível, são avaliadas em relação às coisas. Embora as linguagens funcionais sejam famosas por seu amor por expressões, na verdade é possível ter uma linguagem funcional sem expressões composíveis. Vou inventar um, onde não haja expressões, apenas afirmações.
É praticamente igual ao fornecido antes, exceto que as funções são encadeadas puramente por meio de cadeias de instruções e ligações.
Um estilo de programação centrado em iterador pode ser aquele adotado pelo Python. Vamos usar um estilo puramente iterativo, centrado no iterador:
Isso não é funcional, porque cada cláusula é um processo iterativo e são unidas por pausa explícita e retomada dos quadros de pilha. A sintaxe pode ser inspirada parcialmente em uma linguagem funcional, mas é aplicada a uma incorporação completamente iterativa dela.
Claro, você pode compactar isso:
O imperativo não parece tão ruim agora, hein? :)
O ponto final foi sobre um fluxo de controle mais explícito. Vamos reescrever o código original para fazer uso disso:
Usando iteradores, você pode ter:
Então, qual é o objetivo de uma linguagem funcional se a diferença é entre:
A principal característica definitiva de uma linguagem de programação funcional é que ela remove a mutação como parte do modelo de programação típico. Muitas vezes as pessoas entendem que isso significa que uma linguagem de programação funcional não tem instruções ou usa expressões, mas essas são simplificações. Uma linguagem funcional substitui a computação explícita por uma declaração de comportamento, na qual a linguagem então realiza uma redução.
Restringir-se a este subconjunto de funcionalidade permite que você tenha mais garantias sobre o comportamento de seus programas e isso permite que você os componha com mais liberdade.
Quando você tem uma linguagem funcional, criar novas funções geralmente é tão simples quanto compor funções intimamente relacionadas.
Isso não é simples, ou talvez nem seja possível, se você não controlou explicitamente as dependências globais de uma função. A melhor característica da programação funcional é que você pode criar consistentemente abstrações mais genéricas e confiar que elas podem ser combinadas em um todo maior.
fonte
apply
não é exatamente a mesma operação quefold
oureduce
, embora concorde com a boa capacidade de ter algoritmos muito genéricos.apply
significarfold
oureduce
, mas parece-me que ele tem que ser neste contexto para que possa retornar um boolean.No paradigma procedural (devo dizer "programação estruturada" em vez disso?), Você compartilhou memória mutável e instruções que a lêem / escrevem em alguma seqüência (uma após a outra).
No paradigma funcional, você tem variáveis e funções (no sentido matemático: as variáveis não variam ao longo do tempo, as funções só podem computar algo com base em suas entradas).
(Isso é muito simplificado, por exemplo, os FPLs geralmente têm recursos para trabalhar com memória mutável, enquanto as linguagens procedurais podem muitas vezes suportar procedimentos de ordem superior, então as coisas não são tão claras; mas isso deve dar uma ideia)
fonte
The Charming Python: A programação funcional em Python da IBM Developerworks realmente me ajudou a entender a diferença.
Especialmente para alguém que conhece um pouco Python, os exemplos de código neste artigo nos quais fazer coisas diferentes funcional e proceduralmente são contrastados, podem esclarecer a diferença entre programação procedural e funcional.
fonte
Na programação funcional, a fim de raciocinar sobre o significado de um símbolo (variável ou nome de função), você só precisa saber realmente 2 coisas - o escopo atual e o nome do símbolo. Se você tiver uma linguagem puramente funcional com imutabilidade, ambos são conceitos "estáticos" (desculpe pelo nome muito sobrecarregado), o que significa que você pode ver ambos - o escopo atual e o nome - apenas olhando o código-fonte.
Na programação procedural, se você quiser responder à pergunta qual é o valor por trás,
x
você também precisa saber como você chegou lá, o escopo e o nome por si só não são suficientes. E isso é o que eu veria como o maior desafio porque esse caminho de execução é uma propriedade "runtime" e pode depender de tantas coisas diferentes, que a maioria das pessoas aprende apenas a depurar e não a tentar recuperar o caminho de execução.fonte
Recentemente, estive pensando na diferença em termos do Problema de Expressão . A descrição de Phil Wadler é freqüentemente citada, mas a resposta aceita para essa pergunta é provavelmente mais fácil de seguir. Basicamente, parece que as linguagens imperativas tendem a escolher uma abordagem para o problema, enquanto as linguagens funcionais tendem a escolher a outra.
fonte
Uma diferença clara entre os dois paradigmas de programação é o estado.
Na programação funcional, o estado é evitado. Simplificando, não haverá nenhuma variável com um valor atribuído.
Exemplo:
No entanto, a programação procedural usa o estado.
Exemplo:
fonte