Muitas linguagens de programação modernas suportam algum conceito de fechamento , isto é, um pedaço de código (um bloco ou uma função) que
- Pode ser tratado como um valor e, portanto, armazenado em uma variável, passado para diferentes partes do código, definido em uma parte de um programa e invocado em uma parte totalmente diferente do mesmo programa.
- Pode capturar variáveis do contexto em que está definido e acessá-las quando for posteriormente invocada (possivelmente em um contexto totalmente diferente).
Aqui está um exemplo de encerramento escrito em Scala:
def filterList(xs: List[Int], lowerBound: Int): List[Int] =
xs.filter(x => x >= lowerBound)
O literal da função x => x >= lowerBound
contém a variável livre lowerBound
, que é fechada (vinculada) pelo argumento da função filterList
que tem o mesmo nome. O fechamento é passado para o método da biblioteca filter
, que pode ser chamado repetidamente como uma função normal.
Eu tenho lido muitas perguntas e respostas neste site e, até onde eu entendi, o termo encerramento é frequentemente associado automaticamente à programação funcional e ao estilo de programação funcional.
A definição de programação de funções na wikipedia diz:
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 dados de estado e mutáveis. Ele enfatiza a aplicação de funções, em contraste com o estilo de programação imperativa, que enfatiza as mudanças de estado.
e mais adiante
[...] no código funcional, o valor de saída de uma função depende apenas dos argumentos que são introduzidos na função [...]. A eliminação dos efeitos colaterais pode facilitar a compreensão e a previsão do comportamento de um programa, que é uma das principais motivações para o desenvolvimento da programação funcional.
Por outro lado, muitas construções de fechamento fornecidas pelas linguagens de programação permitem que um fechamento capture variáveis não locais e as altere quando o fechamento é invocado, produzindo um efeito colateral no ambiente em que foram definidas.
Nesse caso, os fechamentos implementam a primeira ideia de programação funcional (funções são entidades de primeira classe que podem ser movidas como outros valores), mas negligenciam a segunda ideia (evitando efeitos colaterais).
Esse uso de fechamentos com efeitos colaterais é considerado estilo funcional ou os fechamentos são considerados uma construção mais geral que pode ser usada tanto para um estilo de programação funcional quanto para um não-funcional? Existe alguma literatura sobre esse tópico?
NOTA IMPORTANTE
Não estou questionando a utilidade dos efeitos colaterais ou de ter encerramentos com efeitos colaterais. Além disso, não estou interessado em discutir as vantagens / desvantagens de fechamentos com ou sem efeitos colaterais.
Estou interessado apenas em saber se o uso de tais fechamentos ainda é considerado estilo funcional pelo proponente da programação funcional ou se, pelo contrário, seu uso é desencorajado ao usar um estilo funcional.
fonte
Respostas:
Não; a definição de paradigma funcional é sobre falta de estado e implicitamente falta de efeitos colaterais. Não se trata de funções de alta ordem, fechamentos, manipulação de lista suportada por idioma ou outros recursos de idioma ...
O nome da programação funcional vem da noção matemática de funções - chamadas repetidas na mesma entrada sempre fornecem a mesma saída - função nullipotent. Isso só pode ser alcançado se os dados forem imutáveis . Para facilitar o desenvolvimento, as funções se tornaram mutáveis (funções mudam, os dados ainda são imutáveis) e, portanto, a noção de funções de ordem superior (funcionais em matemática, como derivadas, por exemplo) - uma função que assume como entrada outra função. Para a possibilidade de funções serem passadas como argumentos, foram adotadas funções de primeira classe ; após estes, para aumentar ainda mais a produtividade, surgiram fechamentos .
Esta é, obviamente, uma visão muito simplificada.
fonte
map
, por exemplo, o que aceita uma função, a aplica a uma lista e retorna uma lista dos resultados.map
não modifica nenhum de seus argumentos, não altera o comportamento da função usada como argumento, mas é definitivamente uma função de ordem superior - se você a aplicar parcialmente, com apenas o parâmetro function, você construiu um nova função que opera em uma lista, mas ainda não ocorreu nenhuma mutação.Não. "Estilo funcional" implica programação sem efeitos colaterais.
Para ver o porquê, dê uma olhada na entrada do blog de Eric Lippert sobre o
ForEach<T>
método de extensão e por que a Microsoft não incluiu um método de sequência como esse no Linq :fonte
ParallelQuery<T>.ForAll(...)
. A implementação de um talIEnumerable<T>.ForEach(...)
é extremamente útil para depurarForAll
declarações (substitua oForAll
comForEach
e remover oAsParallel()
e você pode muito mais facilmente percorrer / depurá-lo)A programação funcional leva as funções de primeira classe ao próximo nível conceitual, com certeza, mas declarar funções anônimas ou passar funções para outras funções não é necessariamente uma coisa de programação funcional. Em C, tudo era um número inteiro. Um número, um ponteiro para dados, um ponteiro para uma função ... tudo apenas ints. Você poderia passar ponteiros de função para outras funções, fazer listas de ponteiros de função ... Heck, se você trabalha em linguagem assembly, funções são realmente apenas endereços na memória onde blocos de instruções da máquina são armazenados. Dar um nome a uma função é uma sobrecarga extra para as pessoas que precisam de um compilador para escrever código. Portanto, as funções eram "de primeira classe", nesse sentido, em uma linguagem completamente não funcional.
Se a única coisa que você fizer é calcular fórmulas matemáticas em um REPL, poderá ser funcionalmente puro com o seu idioma. Mas a maioria dos programas de negócios tem efeitos colaterais. Perder dinheiro enquanto aguarda a conclusão de um programa de longa duração é um efeito colateral. Executar qualquer ação externa: gravar em um arquivo, atualizar um banco de dados, registrar eventos em ordem, etc. requer uma mudança de estado. Poderíamos debater se o estado é realmente alterado se você encapsular essas ações em invólucros imutáveis que eliminam os efeitos colaterais, para que seu código não precise se preocupar com eles. Mas é como discutir se uma árvore faz barulho se cair na floresta sem ninguém lá para ouvi-la. O fato é que a árvore começou na vertical e acabou no chão. O estado é alterado quando as coisas são feitas, mesmo que apenas para relatar que as coisas foram feitas.
Portanto, ficamos com uma escala de pureza funcional, não em preto e branco, mas em tons de cinza. E nessa escala, quanto menos efeitos colaterais, menos mutabilidade, melhor (mais funcional).
Se você absolutamente exigir um efeito colateral ou um estado mutável no seu código funcional, você se esforçará para encapsular o código do resto do seu programa da melhor maneira possível. Usar um fechamento (ou qualquer outra coisa) para injetar efeitos colaterais ou estados mutáveis em funções de outra forma puras é a antítese da programação funcional. A única exceção pode ser se o fechamento for a maneira mais eficaz de encapsular os efeitos colaterais do código para o qual ele é passado. Ainda não é "programação funcional", mas pode ser o armário que você pode obter em determinadas situações.
fonte