A recursão é uma instância de ser "inteligente demais" ao programar?

8

Li vários livros e aprendi com a experiência que otimizar o código até o ponto em que ele é inescrutável ou encontrar uma solução extremamente rápida, mas extremamente complexa para um problema, não é desejável quando se trabalha em equipe ou mesmo quando você está trabalhando. sozinho e precisa entender sua solução inteligente algum tempo depois.

Minha pergunta é: a recursão deve ser tratada da mesma maneira? O programador médio entende a recursão facilmente e, portanto, deve-se usá-la com impunidade ou o programador médio não entende muito bem a recursão e deve ficar longe dela por causa da produtividade geral da equipe?

Eu sei que existem respostas simples de: "Qualquer programador que não entenda a recursão não vale um grão de sal, então não se preocupe com eles", mas eu queria saber se todos vocês têm alguma experiência no mundo real que gostariam de ter. compartilhar que iluminaria a questão mais do que a opinião que acabei de mencionar.

Abadia de Macy
fonte
2
Essa pergunta é bem parecida com programmers.stackexchange.com/questions/24997/…, que também foi feita hoje. Algumas boas respostas lá.
Nicole
4
Como você pode ser um programador comum, se não entende a recursão? (observe a diferença de "qualquer programador")

Respostas:

22

O programador médio entende a recursão facilmente e, portanto, deve-se usá-la com impunidade ou o programador médio não entende muito bem a recursão e deve ficar longe dela por causa da produtividade geral da equipe?

Eu diria que o programador médio entende a recursão perfeitamente. De fato, se o programador se formou em Ciência da Computação ou Engenharia de Software, isso é praticamente garantido. É verdade que existem alguns programadores muito abaixo da média por aí, mas você não os quer em sua equipe.

Nesse caso, a distinção entre um programador médio e um bom programador é saber quando usar recursão e quando não usar. E isso depende do problema que está sendo resolvido E da linguagem usada para resolvê-lo.

  • Se você estiver usando uma linguagem de programação funcional, a recursão é uma solução natural e eficiente para uma ampla gama de problemas. (Regras de otimização da recursão da cauda!)

  • Se você estiver usando uma linguagem processual simples ou OO, a recursão pode ser ineficiente e problemática devido ao excesso de pilha. Portanto, em alguns casos, você escolheria uma solução iterativa em vez de uma solução recursiva. No entanto, em outros casos, a solução recursiva é muito mais simples e elegante que a (possivelmente mais eficiente) solução iterativa seria a "muito inteligente". (Por exemplo, se o problema exigir retorno, construção ou caminhada de árvores / gráficos, etc., a recursão geralmente será mais simples.)

Stephen C
fonte
1
+1 Para comentário de recursão da cauda. Geralmente, uma tentativa de remover a recursão acaba com muitas estruturas de pilha e loops no código, que replicam efetivamente o componente de pilha de chamadas.
Orbling
1
@Orbling - isso é verdade, mas é provável que uma pilha implementada usando uma matriz ou lista de matrizes seja mais escalável que a pilha de chamadas de um encadeamento. Especialmente porque as pilhas de chamadas de encadeamento não podem crescer em muitas implementações de idiomas.
Stephen C
Sim, é um eterno problema de design de funções recursivas. Mais um problema para os designers de linguagem abordarem do que o programador, idealmente.
Orbling 22/03/2013
" Concedido, existem alguns programadores muito abaixo da média por aí ": OK, basta dizer ... Por definição, metade dos programadores estão abaixo da média e metade deles está "muito abaixo" da média.
Lawrence Dol
@ LawrenceDol - Eu nunca vi alguém afirmar que "muito" significa metade de qualquer coisa. Qual é a sua fonte para a sua definição? (Isto também tem que ser feita, porque pedantismo só tem qualquer valor se for baseadas em fatos.)
Stephen C
42

Alguns problemas são naturalmente recursivos. Encontrar uma solução iterativa nesses casos pode realmente ser mais desajeitado e complexo do que os recursivos. Um bom exemplo é qualquer algoritmo que precise percorrer uma estrutura hierárquica em árvore, o que é uma tarefa não incomum na programação.

TL; versão DR: Não.

Bobby Tables
fonte
9
Acordado. É mais perigoso rotular as coisas como "prejudiciais" e ir ao extremo para evitá-las - o que sempre acaba sendo mais confuso e difícil de seguir adiante.
heretik
11

A recursão é um princípio fundamental na maioria das linguagens de programação funcionais. A iteração (loop) em linguagens funcionais geralmente é realizada por recursão.

Ultimamente, as linguagens funcionais viram um renascimento, devido à necessidade de lidar com mais núcleos de processador; linguagens funcionais ajudam a obter esse tipo de simultaneidade, fornecendo maneiras de melhor raciocinar sobre seu programa sem a complexidade envolvida no bloqueio de estruturas mutáveis.

Robert Harvey
fonte
+1 Bom comentário. Embora eu não tenha certeza de que "um renascimento" esteja certo, ou o motivo dos núcleos múltiplos. Eles sempre foram um paradigma favorito daqueles que sabiam sobre eles, mas sua proliferação no mainstream nunca foi grande. As linguagens funcionais acabaram de se tornar mais populares, precisaria de um tópico inteiro para abordar essa questão. ( programmers.stackexchange.com/questions/20036/… que você já leu)
Orbling
11

Alguns problemas, como percorrer uma estrutura em árvore (percorrer, digamos, uma estrutura de diretórios inteira, em vez de, digamos, procurar um nó específico da Árvore B), são ideais para usar a recursão; os equivalentes não recursivos geralmente simplesmente adicionam a complicação de gerenciar sua própria pilha.

Nesses casos, a recursão é a solução melhor, mais simples e mais fácil de entender.

Lawrence Dol
fonte
7

Eu diria que use a recursão onde for apropriado, mas sempre procure maneiras de evitar recursões explícitas.

Por exemplo, se você achar necessário atravessar manualmente uma estrutura em árvore, sim, você deve usar a recursão. Se alguém é burro o suficiente para não entender uma travessia recursiva da árvore, não fará nem cabeça nem cauda da versão iterativa.

Mas uma opção melhor é usar um iterador que abstraia a recursão até o ponto em que tudo que você vê é "Eu executo essa operação em tudo na árvore".

Anon.
fonte
1
Verdadeiro (e +1), mas, é claro, alguém precisa escrever a abstração.
Lawrence Dol
1
Como o @Software Monkey diz, ainda deve geralmente ser codificado recursivamente, mas a abstração para um iterador para "uso" é boa.
Orbling
1
+1 para o ponto em que alguém que não entenderia a versão recursiva provavelmente não entenderá a versão iterativa. Infelizmente, essa pessoa também não perceberia que não entende a versão iterativa.
Larry Coleman
3

Recursão, é o mecanismo mais simples do ponto de vista de limpeza de código. Se a velocidade é absolutamente essencial, talvez você possa usar uma matriz 2D de parâmetros de problemas. Gerar um processo filha é simplesmente anexar outro item à matriz. Certa vez, fiz um solucionador tridiagonal de montador, que foi um grande negócio naquela época. O contexto necessário por instância era de 8 palavras por nível, e cada subproblema tinha um terço do tamanho do anterior. Essa "biblioteca" era popular apenas porque superava todas as outras implementações existentes. Mas, essa é uma situação bastante rara na programação, portanto você não precisa sucumbir à "otimização prematura", apenas porque esta solução está disponível. Obviamente, para algumas coisas, seu terrível exagero, como o exemplo da recursão 101 "calcula o fatorial". Mas para a maioria dos aplicativos,

Eu tenho um verificador ortográfico simples que uso em um aplicativo (onde quero dar dicas sobre como corrigir erros de ortografia menores), onde calculo a "distância" entre duas strings, permitindo exclusões e adições. Isso leva a uma estrutura de árvore potencialmente grande e os galhos são cortados, pois só nos preocupamos com correspondências fechadas. Com recursão, são talvez vinte linhas de código (eu tenho as versões Fortran e C). Eu acho que seria confuso caso contrário. Heck, era muito mais fácil programar / verificar erros, do que pensar nessa árvore!

Omega Centauri
fonte
0

Eu entendo, mas nunca o usei explicitamente. Eu acho que qualquer um que se autodenomina um programador deve saber ou aprender o que é tanto quanto precisa saber o que é a pilha e a pilha. Ei, todo mundo precisa saber como o mínimo / máximo funciona no jogo da velha, por meio de recursão sofisticada.

johnny
fonte