Funções de Primeira Classe

11

Comecei a dar uma olhada séria no Lisp neste fim de semana (com o que quero dizer que só aprendi o Lisp e não voltei a projetos em C #) e devo dizer que eu amo isso. Eu brinquei com outras linguagens funcionais (F #, Haskell, Erlang), mas não senti a atração que Lisp me deu.

Agora, enquanto continuo aprendendo o Lisp, comecei a me perguntar por que linguagens não funcionais não suportam funções de primeira classe. Eu sei que linguagens como C # podem fazer coisas semelhantes com delegados e, até certo ponto, você pode usar ponteiros para funções em C / C ++, mas existe uma razão pela qual isso nunca se tornaria um recurso nessas linguagens? Existe uma desvantagem em criar funções de primeira classe? Para mim, é extremamente útil, por isso estou perdido porque mais idiomas (fora do paradigma funcional) não o implementam.

[Editar] Agradeço as respostas até agora. Como me foi mostrado que muitos idiomas agora suportam funções de primeira classe, refiz a pergunta: por que demoraria tanto tempo para os idiomas implementá-los? [/Editar]

Jetti
fonte
3
Eu discordo que o C # pode fazer "coisas semelhantes". Eu diria que tem funções de primeira classe para todos os efeitos (o que estraga sua premissa). Ele possui uma sintaxe para literais de funções, você pode inserir funções em variáveis ​​etc.
Logan Capaldo
@Logan - Eu estava debatendo sobre a inclusão de exemplos em C #, mas decidi com base nessa entrada da wikipedia . De acordo com a entrada, não existem funções verdadeiras de primeira classe, pois "já que os objetos que mantêm o estado dinâmico da função devem ser construídos manualmente". No entanto, se essa é uma afirmação incorreta, eu adoraria saber o porquê! (Afinal de contas, eu estou aqui para aprender e não ser preso em meus caminhos!)
Jetti
2
essa entrada da Wikipedia está desatualizada. Um C # moderno fornece uma lambda adequada.
SK-logic
Eu acho que esse parágrafo está mal escrito. Parece estar dizendo que os functores C ++ não são de primeira classe e nem são delegados em C #? Embora eu possa concordar com o argumento para functors, não tenho certeza se concordaria com delegados em C #. Ele também diz "(veja lambda lifting)", que é uma declaração sobre essas linguagens que suportam fechamentos lexicais em vez de "funciona como valores". Você pode ter um sem o outro. Mesmo se for esse o caso, não é verdade para o C #, ele tem fechamentos lexicais. Parte do problema é "função de primeira classe" pode ser um termo vago.
Logan Capaldo
1
@Logan & SK-Logic - Agradeço seu feedback e permaneça construtivo. Ainda estou aprendendo e é muito bom não ser inflamado, então eu aprecio isso. Muito obrigado pelos comentários e respostas!
Jetti 27/02

Respostas:

5

C #, VB.NET, Python, JavaScript, agora até C ++ 0x fornecem funções de primeira classe.

Atualizar:

Uma implementação de fechamentos requer o levantamento de lambda - uma técnica originalmente bastante estranha para os programadores imperativos. As funções adequadas de primeira classe (que incluem fechamentos) requerem pelo menos algum suporte do tempo de execução e da VM. Também levou algum tempo para adotar as antigas técnicas funcionais no mundo imperativo.

E a parte mais importante - as funções de primeira classe dificilmente podem ser usadas se não houver coleta de lixo presente. Foi introduzido em uma programação em massa apenas recentemente, com Java e, conseqüentemente, .NET. E a abordagem Java original era simplificar demais a linguagem para mantê-la compreensível pelos codificadores comuns. O .NET foi o primeiro a seguir, e apenas recentemente se separou dessa direção (IMHO, bastante justificada e apropriada).

Todos esses conceitos levam tempo para serem digeridos pela indústria.

SK-logic
fonte
Eu editei a pergunta original com base nas respostas.
Jetti 27/02 '17
Funções de primeira classe! = Fechamentos (e o GC é muito mais necessário para o último). Embora, sim, eles estejam intimamente relacionados e você raramente, se é que alguma vez, os vê separados.
@delnan, sem pelo menos alguma forma de fechamento lexical, as funções não podem ser compostas nem construídas em tempo de execução, o que é obrigatório para uma definição de funções de primeira classe.
SK-logic
Não. Você pode impedir a referência a variáveis ​​de escopos anexos (ou copiar os valores da variável referida no momento da criação da função - não sei se isso conta como fechamento). O resultado não é particularmente útil, mas as funções ainda podem ser construídas em tempo de execução sem serem fechadas e, portanto, você teria funções (estranhas) de primeira classe.
1
@ SK-logic: C ++ 0x fornece fechamentos sem coleta de lixo com o truque usual -> se a variável sair do escopo e você ainda estiver se apegando a uma referência, usar a referência é um comportamento indefinido. Portanto, é possível ... apenas coloca o honus no desenvolvedor.
Matthieu M.
5

Funções de primeira classe são muito menos interessantes sem fechamentos.

Os fechamentos não são realmente possíveis sem algum tipo de gerenciamento dinâmico de escopo (coleta de lixo). Uma das coisas que faz com que o C / C ++ seja de alto desempenho é o fato de ser muito mais fácil compilar uma linguagem na qual você gerencia manualmente a memória, de modo que tira o C / C ++ da equação.

E então sim, há a questão do impacto no POO. Você não tem mais uma separação de métodos e propriedades. Os próprios métodos são propriedades que aceitam funções como valores. Nesse contexto, o que realmente significa sobrecarregar métodos, já que você pode trocar as coisas bobas a qualquer momento. Você pode realmente adicionar isso ao Java, por exemplo, sem introduzir uma grande mudança de paradigma em toda a linguagem? Onde está o contrato ou o senso de segurança (falso da OMI) ao saber que a construção garante que sempre funcionará da mesma maneira todas as vezes? Pode fazer sentido tratar funções vinculadas a objetos como métodos como um organismo diferente em linguagens que permitiam que as funções existissem independentemente em primeiro lugar, mas em Java isso não é realmente uma opção.

Em JavaScript, OOP e funcional estão muito interligados e, pessoalmente, acho difícil ver funções de primeira classe como qualquer coisa, exceto em linguagens onde elas não estavam. Mas isso requer várias outras mudanças de mudança de paradigma, incluindo altos níveis de mutabilidade nos objetos e em seus próprios métodos, além de poder chamar funções como se fossem membros de qualquer objeto em movimento.

Os idiomas não são apenas conjuntos de ferramentas cheios de truques para fazer as coisas na maior parte do tempo. Eles são paradigmas. Conjuntos de idéias, estratégias e opiniões que se combinam de uma maneira que está conectada (ou parece conectada). Em muitos casos, funções como substantivo e verbo realmente simplesmente não se encaixam no paradigma ou, na melhor das hipóteses, são um ajuste imperfeito.

Dito isto, sinto como se estivesse perdendo um braço quando forçado a codificar sem eles.

Erik Reppen
fonte
Você pode tratar todos os métodos como selados ou apenas selar os que mais lhe interessam, e ficará bem.
Alexei Averchenko
@AlexeiAverchenko Estou feliz em dizer que não tenho 100% de certeza do que você quer dizer com isso. Desculpe, perdi seu comentário até agora. Pesquisando "métodos selados".
Erik Reppen
4

Não é realmente impossível. Mas é mais um recurso, e o orçamento de complexidade é limitado. Pode ser considerado desnecessário (ou nem ocorrer) ao designer da linguagem - "por que diabos precisaríamos transmitir funções? Essa linguagem é para programar um sistema operacional!". Também pode ser necessário um esforço significativo para mesclar com o restante do idioma. Por exemplo, um tipo de função pode exigir acréscimos sérios ao sistema de tipos (por exemplo, em Java), ainda mais se você estiver sobrecarregando (obrigado @Renesis por apontar isso). Você também precisa fornecer algum código de biblioteca para fazer uso do viável - ninguém quer se definir map.

Também poderia dificultar a realização de outros objetivos da linguagem:

  • Torna-se "mais difícil" otimizar (não é realmente mais difícil em muitos casos, mas requer abordagens diferentes daquelas com as quais você está acostumado). Por exemplo, se funções globais puderem ser reatribuídas, você deve provar que fnunca é reatribuído antes de incorporá-lo.
  • Da mesma forma, se você criar funções com objetos com todos os recursos, precisará de um compilador inteligente e JIT para remover a sobrecarga associada a isso e tornar a chamada tão eficiente (em termos de velocidade e espaço) quanto pressionar argumentos e endereço de retorno e pular para algum endereço.
  • Como já mencionado, é outro recurso completo e os primeiros passos para apoiar outro paradigma - se você deseja uma linguagem simples, talvez não possa se dar ao luxo de adicionar funções de primeira classe sem lançar outras coisas (o que você pode considerar muito mais importante) Fora.
  • Talvez simplesmente não se misture bem com o resto da linguagem. Se você projetou a linguagem para, por exemplo, ser a melhor encarnação do OOP desde o Smalltalk, você pode se concentrar nisso, em vez de oferecer outro paradigma muito diferente. Especialmente se for difícil integrar os dois (veja acima). N paradigmas bem executados são mais agradáveis ​​de programar do que os paradigmas N + 1 mal executados.

Do mesmo modo, pode-se perguntar por que qualquer linguagem de programação L1 não possui o recurso F da linguagem L2 muito diferente.


fonte
1

Penso que o primeiro problema é um mal-entendido de que Orientado a Objetos e Funcionais não podem ser misturados. Uma lista rápida de idiomas descritos, pelo menos pela Wikipedia, como ambos: JavaScript , ActionScript , Python , C # , F # .

O segundo problema parece ser uma definição de funções de primeira classe - por que você não considera C # tê-las, por exemplo?

Como não sou especialista em linguagem funcional, por favor, corrija-me nos comentários, se estiver errado, mas meu entendimento é que a inclusão de funções de primeira classe define mais ou menos a si mesma, define se uma linguagem suporta um paradigma funcional .

Qual é a verdadeira questão?

Portanto, entendendo que as linguagens orientadas a objetos também podem ser funcionais, e essas linguagens contêm funções de primeira classe, parece que a pergunta que você está procurando é por que algumas linguagens orientadas a objetos não contêm funções de primeira classe?

Sobrecarga de função

Uma das principais razões para isso é a dificuldade de definir funções de primeira classe quando a linguagem também optou por oferecer suporte à sobrecarga de funções (exemplo em Java):

public int dispatchEvent(Event event);
public int dispatchEvent(String event, Object data);

A qual dispatchEventfunção uma variável se referiria?

Programação baseada em classe

A programação baseada em classe não impede que um idioma suporte objetos de primeira classe, mas pode torná-lo mais confuso ou adicionar perguntas a serem respondidas.

O ActionScript, por exemplo, como uma linguagem ECMAScript começou em um paradigma muito mais funcional como o JavaScript. As funções não eram inerentemente vinculadas a objetos, elas poderiam ser chamadas essencialmente com qualquer objeto, pois seu escopo no momento da execução.

Ao adicionar classes (não dinâmicas), você tem funções inerentemente ligadas a uma instância, não apenas a própria classe. Isso lança algumas rugas na especificação de Function.applyque eu sinceramente não procurei descobrir como eles lidaram com isso.

Nicole
fonte
3
"A inclusão de funções de primeira classe faz mais ou menos uma linguagem funcional". - errado. É um pré-requisito, sim. Mas há muito mais, como (para citar apenas três) evitar estado mutável, o foco nas expressões e na aplicação de funções, em vez de declarações sequenciais e a ênfase na transparência referencial.
@ delnan Você deveria seguir a Wikipedia correta ... A menos que "linguagem funcional" e "linguagem que apóie um paradigma funcional" sejam duas coisas diferentes.
27611 Nicole
1
@Rensis: São coisas diferentes. Você pode criar algo como objetos (mesmo incluindo vtables) em C, mas não é bonito. Passar de "tem funções de primeira classe" para "é um idioma funcional" não é tão ruim assim, mas ainda é uma diferença. Além disso, o wiki (corretamente) indica na página que você vinculou a "Esses recursos são necessários para o estilo de programação funcional [...]". (ou seja: não "o recurso de definição") e lista vários outros recursos na página no FP.
@ delnan, tudo bem, eu corrigi minha redação. Eu apenas quis dizer que a condição para um idioma ser considerado como suporte a um paradigma funcional - assim como a página da Wikipedia para cada um desses idiomas que listei. Eu não quis dizer que isso é tudo que faz parte do estilo de programação funcional .
27711 Nicole
0

Eu me perguntei a mesma coisa. Quando estou em um idioma com lambdas, uso-os MUITO. Até o PHP melhora quando você percebe que pode fazer um fechamento com o php 5.3 (não é tão bom quanto o lisp, mas ainda melhor)

Zachary K
fonte