A programação funcional adiciona complexidade ao código? [fechadas]

17

Durante todo o ano passado, eu escrevi o código Scala (vindo de Java). Gostei muito de como você poderia criar código mais simples e limpo, com vals, classes de caso, funções map / filter / lambda, implícitos e a inferência de tipo. Eu o usei principalmente para um aplicativo baseado em Akka .

Este ano, estou em um projeto Scala com uma nova equipe, que realmente gosta de programação funcional. Eles usam intensamente o Scalaz , e o código é preenchido em todos os lugares com aplicativos, limites de contexto, mônada de leitor / gravador / estado, até o método principal é "encapsulado" em uma mônada de E / S. O raciocínio deles é que isso faz o compilador "trabalhar para nós" ao afirmar que o código está correto e que cada função está livre de efeitos colaterais.

Mesmo assim, do meu ponto de vista, toda essa sintaxe realmente atrapalha a lógica dos negócios. Por exemplo, um tipo de "MyBusinessObject" é bom, assim como tipos "List [MyBusinessObject]", "Option [MyBusinessObject]" ou mesmo "Future [MyBusinessObject]". Todos eles têm um significado e propósito claros. Por outro lado, código como:

def method[M[_]: Applicative] = {
  case (a, b) => (ca[M](a) |@| cb[M](b)) {
    case t @ (ra, rb) =>
      if (ra.result && rb.result) t.right
      else t.left
  }
}

isso adiciona complexidade ao programa ou sou apenas eu que não estou acostumado a esse modo de programação?

Luciano
fonte
6
Qual é a sua pergunta objetivamente responsável?
Deer Hunter
1
Parece que leva a uma tonelada de código com nomes de variáveis ​​de uma ou duas letras. Parece um pouco APL. Isso não é um complemento.
precisa saber é o seguinte
3
Comecei a brincar com Haskell no ano passado. Parecia incrivelmente complexo na época, quando eu não entendia conceitos como curry, functors, mônadas etc. O Haskell é semelhante ao Scalaz, pois possui muitas funções simbólicas curtas, como >>=e <$>, que não significam nada até você sabe o que eles fazem. Depois de aprender o que eles significam, no entanto, eles lêem muito naturalmente e rapidamente para mim agora. Não é realmente uma resposta, apenas minha experiência objetiva com coisas assim. Também uso o Scala, mas não tenho experiência com a biblioteca Scalaz.
KChaloux #
3
Você não está familiarizado com os idiomas. @ user949300 variáveis ​​curtas não são realmente um problema para muitos códigos funcionais (pense nas convenções de estilo de matemática!). Leia também o blog de Tony Morris para uma discussão mais aprofundada sobre o que melhor transmite significado, tipos ou nomes de variáveis ​​detalhados.
Andres F.
3
@ user949300: nomes curtos de variáveis ​​são preferidos localmente, isso é o mesmo nos mundos funcionais e imperativos (você não escreveria for(i=0; i<7; ++i) { trivialOperation(i); }com alguma trivialOperationCountvariável incômoda , não é?) Agora, linguagens de programação funcionais com correspondência de padrões às vezes introduzem mais algumas variáveis ​​nas quais você acabei de escrever as chamadas do método acessador no OO. O resultado é geralmente mais conciso; talvez um pouco menos auto-explicativo, mas procurar a declaração de dados normalmente deixa claro rapidamente. A digitação estática ajuda muito, não é como no APL.
precisa saber é o seguinte

Respostas:

37

Isso não tem nada a ver com programação funcional - você pode encontrar esse tipo de situação no contexto de qualquer outra linguagem de programação - desenvolvedores que amam tanto as construções avançadas da linguagem "sua" que ignoram qualquer senso comum sobre legibilidade e simplificação. Eu encontrei uma situação dessas em C, C ++, Perl, Java, C #, Basic e outras linguagens não funcionais. Não é a programação funcional que adiciona complexidade ao código - os programadores fazem.

Não me interpretem mal, eu não recomendo evitar recursos avançados de linguagem - mas é importante encontrar o equilíbrio certo no contexto fornecido. Ao escrever uma biblioteca genérica para o uso de> 100.000 desenvolvedores em todo o mundo, existem medidas diferentes a serem aplicadas, como quando você está escrevendo um gerador de relatórios individual apenas para o escritório local.

Doc Brown
fonte
7
Também tem muito a ver com a comunidade. Para um desenvolvedor com experiência em Java ou C #, o código é pouco compreensível (e sua comunidade também não o entenderia). Mas se você escreve Haskell, por exemplo, e não usa mônadas, aplicadores, functores e assim por diante, está desconcertando a comunidade dessa linguagem. A "naturalidade" do código não é inerente, mas relativa à sua comunidade e práticas estabelecidas.
Andres F.
1
Isso é difícil de ver, porque a maioria de nós tem antecedentes imperativos, o que às vezes nos leva a fazer suposições erradas sobre o que é natural.
Andres F.
basta olhar para a biblioteca SLT C ++, que poderia ser escrito para ser muito mais legível para o amador
aberração catraca
@ratchetfreak: Eu acho que você quer dizer STL. Eu acho que este é um exemplo muito bom (e, de fato, eu tinha isso em mente na minha resposta). O uso de meta-programação de modelos faz muito sentido quando você é um programador de STL, porque torna o STL mais reutilizável. E as pessoas que precisam manter esse código também são normalmente usadas para modelar a metaprogramação. O uso da metaprogramação de modelos de maneira STL em todo o aplicativo de negócios padrão pode facilmente levar a códigos complicados e difíceis de manter. Pode-se certamente encontrar casos (raros) em que o TMP é bom, mesmo em aplicativos de negócios, de cours.
Doc Brown
@DocBrown sim, a dislexia surgiu na hora errada, mas, honestamente, se eu tivesse meia mente (e muito mais tempo do que tenho agora), poderia reescrever muitos dos corpos das funções para ficarem mais legíveis.
roquete aberração
7

Eu diria que você não está acostumado com a maneira como eles codificam é pelo menos parte da imagem. Estou em uma situação semelhante a você (vindo de C # para F # e trabalhando com pessoas com background de Haskell) e, embora eu ache uma experiência interessante, tenho momentos em que estou batendo a cabeça na parede, desembaraçando um composição de função sem ponto particularmente complicada apenas para entender o que está acontecendo lá. É uma coisa cultural.

Quanto a saber se esse código específico adiciona complexidade ao programa - eu não sei. Concordou que um pedaço de código genérico pode ser complexo por si só. Mas é um utilitário, não uma parte da lógica de negócios. Se você quiser saber se isso torna a base de código mais complexa ou mais simples, você teria que imaginar como ela ficaria sem essa parte do código. Geralmente é o caso de construções tão genéricas que elas mesmas são complexas, mas é uma complexidade que você pode ajustar em uma única tela. Ao mesmo tempo, eles tornam toda a base de código um pouco mais simples. Este é particularmente o caso das mônadas.

Por outro lado, também pode ser um caso de 'arte pela arte', como sugere @Doc Brown. Também não pode descartar.

scrwtp
fonte
5

Eu argumentaria que, em geral, a programação funcional reduz a complexidade, eliminando o estado mutável, reduzindo assim o número de casos que devem ser considerados ao tentar entender como uma seção do código funciona.

No entanto, a programação funcional possibilita graus mais altos de abstração e, embora um código altamente abstrato possa ser extremamente útil, também pode ser difícil de entender porque, por definição, é separado do contexto que você usaria normalmente para orientar seu entendimento. Seu comentário "Todos têm um significado e propósito claros" sobre objetos de negócios é indubitavelmente verdadeiro, mas é realmente um reflexo do fato de que essa lógica é muito específica para uma necessidade e contexto que você já entende. A existência de um construto como o Monad permite que você faça algo muito útil com pouco esforço, mas a web está repleta de páginas tentando explicar o que é um Monad. Isso é abstração para você.

Além disso, Scalaz foi escrito por pessoas que comem e respiram FP há muito tempo; eles queriam trazer a funcionalidade disponível em Haskell para Scala. Ao fazer isso, eles não tentaram ser pedagógicos. Scalaz faz uso de um vocabulário e estilo que parecem claros e diretos para os autores, mas estranhos para os não iniciados. Os métodos que são intrigantes para o resto de nós pareciam tão óbvios para os autores, dados os antecedentes de Haskell, que nem sequer mereciam um comentário.

Além disso, como uma linguagem de programação funcional, o Scala tem algumas falhas (em parte porque a JVM tem deficiências) que forçaram os autores do Scalaz a escrever código mais feio em alguns casos. Por exemplo, a falta de eliminação geral de chamadas de cauda força o uso de trampolins em algum código, e a falta de um "sistema de tipos" pode complicar as assinaturas de tipos.

E, finalmente, Scalaz faz um ótimo uso de si mesmo. Isso pode ser pensado como um sinal de seu poder, mas para os não iniciados, a fonte pode ser um enigma - qualquer código aleatório que você observe provavelmente fará uso de algo que lhe pareça estranho.

Mantenha-se firme. E isso pode ajudar.

AmigoNico
fonte
-4

Isso adiciona complexidade ao programa ou apenas você não está acostumado a esse modo de programação?

Por que você acha que essas possibilidades não são a mesma coisa?

Um código bem escrito pode ser lido por pessoas que não estão familiarizadas com a linguagem de programação específica. Algumas linguagens (BASIC, Pascal, etc) podem ser lidas e entendidas por alunos que nunca viram linguagens de programação antes.

Se alguém que tem experiência com outros idiomas e experiência com Scala (e que suponho que trabalhe com Scalaz por pelo menos uma semana e tenha colegas para explicar as coisas mais complicadas) ainda esteja confuso; então isso prova que adicionou complexidade.

Brendan
fonte
11
Isso simplesmente não é verdade:"Well written code can be read by people who aren't familiar with the specific programming language."
Andres F.
@ Andres: É verdade ... até certo ponto. Um código bem escrito separará a lógica de negócios dos detalhes da implementação, e a lógica de negócios deve ser legível, porque a maior parte do que está fazendo é fazer chamadas diretas para funções auxiliares bem nomeadas. Esses auxiliares podem usar todos os tipos de recursos de idioma, é claro, e exigem experiência pesada com o idioma e as bibliotecas para entender.
Ben Voigt
4
Eu acredito que o seguinte é APL idiomática: x[⍋x←6?40]. O que você acha que faz? Eu com certeza não teria sabido ...
bdesham 04/04
3
@Brendan Apenas dentro do mesmo paradigma (e mesmo assim, às vezes não). Por exemplo, Prolog, Java e APL são tão diferentes que eu argumentaria que, se você conhece apenas uma dessas (e nenhuma outra linguagem), não pode ler as outras duas, por mais que conheça a primeira. (Sério, no exemplo de bdesham, como o diabo que você deveria interpretar "árvore de natal" se você não sabe qualquer APL?)
Izkata
1
Brendan, sua definição de bem escrito não é padrão. Bem escrito é sempre relativo ao idioma e à sua comunidade. Um programa na linguagem X é bem escrito, se não é de buggy, é eficiente e claro ... para o público em questão! Isso se aplica à linguagem escrita em geral, a propósito: sempre conheça seu público. O que é adequado para (digamos) um artigo científico provavelmente não é adequado para um e-mail para sua mãe.
Andres F.