Você pode aprender programação funcional em C? [fechadas]


9

Como resultado da discussão de comentários aqui , pergunto-me se você pode aprender Programação Funcional em C?


30
Independentemente de saber se você pode ou não, não deveria .
R. Martinho Fernandes

27
Absolutamente! O primeiro passo é escrever um intérprete Lisp ;-)
Ferruccio

Se eu entendi direito, a pergunta deveria ter sido sobre aprender vários conceitos com pseudocódigo, sem nenhuma linguagem real.
SK-logic

@ SK-logic: Para dizer o mínimo, muito poucos programadores aprenderam a programar apenas com pseudocódigo, a maioria precisava sujar as mãos e os rostos cheios de mensagens de erro do compilador / intérprete.
SBI

4
@sbi, alguns dos melhores programadores aprenderam programação quando os compiladores não tinham nenhuma mensagem de erro. A codificação em cartões perfurados requer um pouco de compreensão do que você está fazendo muito antes de ter a chance de executar o código. E é desnecessário mencionar que a base para a programação funcional foi estabelecida muito antes de um primeiro computador ser construído.
SK-logic

Respostas:


21

Obviamente, você pode fazer programação funcional em C. Em teoria, você também pode aprender princípios de programação funcional em C, mas a linguagem não facilita.

Presumo que você tenha pelo menos um pouco de experiência em OOP; se o fizer, lembre-se de que o POO pode ser feito em C, incluindo polimorfismo, getters / setters, regras de visibilidade, etc. etc., mas é bastante doloroso fazê-lo e você precisa conhecer OOP e C por dentro. fora para retirá-lo. É o mesmo com a FP.

O que você deve fazer é primeiro aprender uma linguagem de programação funcional (a maioria delas possui regras de sintaxe surpreendentemente simples; não é a sintaxe que as torna difíceis de aprender) e depois deixar sua sabedoria recém-adquirida influenciar a maneira como você escreve C.


Conforme solicitado, algumas coisas que você pode aprender com o FP e aplicar em, digamos, C, C ++ ou Java:

  • Evitar estado, especialmente estado mutável compartilhado
  • Aprecie funções puras
  • Apreciar avaliação preguiçosa
  • Ser capaz de modelar em termos de verbos em vez de substantivos
  • Ser capaz de abordar problemas de forma recursiva e iterativa
  • Usando funções de ordem superior
  • Pensar nas funções como apenas outro tipo de valor, que você pode transmitir e combinar com outros valores
  • Usando funções de primeira classe como uma alternativa ao polimorfismo baseado em objetos

11
Você pode fornecer exemplos específicos de como os programadores de C / C ++ / Java podem se beneficiar da sabedoria do LISP. Faz sentido na teoria, mas estou procurando algo concreto.
Job

@Job, Que benefício concreto pode haver? Isso expande suas mentes e talvez os faça pensar em um estado mutável excessivo como uma coisa ruim, o que mais você poderia pedir?
dan_waterworth

Então, posso concluir com isso que, embora seja possível aprender (alguns) FP em C, não faz sentido fazer isso?
SBI

@ Job: Eu aprendi FP quando aprendi LISP como um estudante há muitos anos. Cerca de uma década depois, apliquei FP na meta-programação de modelos.
SBI

11
@sbi, minha maneira favorita de aprender novos idiomas e conceitos é implementando-os. E C é uma linguagem bastante decente para implementar um compilador. Então, sim, você pode aprender FP com C.
SK-logic

11

C pode ser hackeado para oferecer alguns conceitos funcionais:

Esta questão StackOverflow lhe dirá mais. Mas, embora pareça possível fazer programação funcional (ou um grande subconjunto de) em C, hacks e extensões de compilador e qualquer que seja a melhor maneira de aprender sobre um conceito.

Para realmente aprender a programação funcional, sua melhor aposta é uma das linguagens de programação funcional mais importantes, como Lisp e seus dialetos ( Clojure , Scheme ), Erlang e Haskell . Qualquer uma dessas são ferramentas perfeitas que funcionam dentro da mentalidade de programação funcional. O F # também é um bom candidato se você possui um background .Net, mas é uma linguagem de paradigmas múltiplos, não estritamente uma linguagem de programação funcional.


Como tdammers observa nos comentários:

Na verdade, LISP, clojure e esquema também são multiparadigmas; Haskell, apesar de ser puro e preguiçoso por padrão, também permite programação imperativa em um contexto monádico e possui amplo suporte para processamento simultâneo. Todos eles possuem mecanismos que implementam grande parte da sabedoria reunida no mundo OOP - encapsulamento, herança, responsabilidade única, composição etc. Não se trata tanto de uma linguagem PERMITIR outros paradigmas; é sobre qual paradigma forma o ponto de partida de uma linguagem.

Que eu saiba, o Lisp e seus dialetos e Erlang são melhores candidatos do que o F # porque incentivam a programação funcional em relação a outros paradigmas, o que o tdammers afirma lindamente como o ponto de partida da linguagem . O F # abrange programação funcional, mas não o encoraja sobre seus outros paradigmas suportados, imperativos e oo programação.


Em relação à sua última frase: Nesse caso, eu argumentaria que o F # é um candidato melhor porque não o prenderá em uma mentalidade funcional. Em uma linguagem multiparadigma, quando você começa a martelar parafusos, pode simplesmente mudar para uma chave de fenda. Quando preso em um único paradigma, você pode perder a diferença entre o parafuso e o prego.
R. Martinho Fernandes

Bem, a questão é como aprender a programação funcional, não a programação. Suponho que o op tenha alguma experiência em uma linguagem de paradigmas múltiplos e deseje a maneira mais eficiente de aprender programação funcional; nesse caso, o F # é um bom candidato, mas não um perfeito. Preso em um único paradigma é obviamente a melhor maneira quando você procura aprender sobre esse único paradigma, pois não precisa lidar com tudo o que não é.
yannis

Acredito que aprender quando o paradigma é adequado e quando é inadequado para uma determinada tarefa faz parte da aprendizagem, talvez a mais importante.
R. Martinho Fernandes

4
Na verdade, LISP, clojure e esquema também são multiparadigmas; Haskell, apesar de ser puro e preguiçoso por padrão, também permite programação imperativa em um contexto monádico e possui amplo suporte para processamento simultâneo. Todos eles possuem mecanismos que implementam grande parte da sabedoria reunida no mundo OOP - encapsulamento, herança, responsabilidade única, composição etc. Não se trata tanto de uma linguagem PERMITIR outros paradigmas; é sobre qual paradigma forma o ponto de partida de uma linguagem.
tdammers

2
@MartinhoFernandes: Alguém poderia argumentar que estar preso em um único paradigma é o perfeito maneira de aprender quando é realmente uma dor na bunda :-)
Jörg W Mittag


2

TL; DR

A programação funcional é sobre fechamentos e suas aplicações. A menos que alguém possa lhe mostrar uma biblioteca de fechamento de descida para C, esqueça de usar o C para aprender a programação funcional.

O que é programação funcional?

O principal conceito de programação funcional é a noção de fechamentos que, grosso modo, captura uma função juntamente com as ligações das variáveis. Além do uso generalizado de fechamentos, existem algumas outras características distintivas na programação funcional, como o uso de funções recursivas e valores imutáveis ​​(ambos funcionam bem juntos). Esses traços são mais uma questão cultural do que qualquer outra coisa, e não há obstrução técnica para usá-los em praticamente qualquer idioma; é por isso que me concentro nos fechamentos na minha resposta: nem todo idioma permite criar fechamentos com facilidade.

Três ilustrações da utilidade dos fechamentos

Um uso típico de fechamentos é a implementação de mecanismos de privacidade. Por exemplo, o código Javascript - nos exemplos que escolhi o Javascript porque é uma linguagem funcional com a chamada "sintaxe do tipo C" e sua pergunta sugere que você está familiarizado com o C:

create_counter = function()
{
  var x = 0;
  var counter = function()
  {
    ++x;
    return x;
  };
  return counter;
}

Então com

a = create_counter();
b = create_counter();

nós temos duas funções ae bcontando coleções disjuntas. O ponto do exemplo é que as variáveis xsão capturadas pelo fechamento que define o counterfechamento e cada vez que um novo counterfechamento is instantiated by the function, it gets its fresh own idea of whatx` é.

Outro uso típico de fechamentos é a definição de aplicações parciais de funções. Suponha que tenhamos um recurso de relatório semelhante à syslogimplementação de uma função

var log = function(priority, message) {

};

onde os argumentos prioritye messagese espera que sejam cordas, sendo o primeiro um dos "debug", "info"e assim por diante. Podemos definir uma fábrica de logs como esta:

var logWithPriority = function(priority) {
  return function(message) {
    log(priority, message);
  };
};

e use-o para definir versões especializadas do nosso recurso de log:

var debug = logWithPriority("debug");
var info = logWithPriority("info");

Isso é muito útil, porque em vez de escrever forloops propensos a erros como este

for(i = 0; i < journal.length; ++i) {
   log("info", journal[i]);
}

podemos escrever o limpador, mais curto e muito mais simples (não existe i, isso é muito melhor):

journal.forEach(logWithPriority("info"));

Um terceiro campo importante de aplicação de fechamentos é a implementação de avaliação lenta - observe que o suporte a idiomas especiais pode proporcionar uma melhor implementação.

Uma função preguiçosa, em vez de executar uma computação direta, retorna um fechamento que pode ser chamado (ou "forçado" no jargão da preguiça) a executar a pergunta. A motivação para fazer isso é que ele separa a preparação de uma computação e a execução de uma computação. Um exemplo prático disso é a compilação de expressões regulares: se um programa compilar muitas expressões regulares no momento da inicialização, precisará de muito tempo para iniciar. Se, em vez disso, compilamos preguiçosamente as expressões regulares e as forçamos conforme necessário, nosso programa pode ser iniciado rapidamente. Obviamente, expressões regulares podem ser substituídas aqui por qualquer estrutura que exija um tempo considerável de inicialização.

Aqui está como implementar uma avaliação lenta com fechamentos. Considere a implementação clássica da função arrayMax retornando o máximo em uma matriz:

function arrayMax(array) {
  return array.reduce(function(a, b) {
    return Math.min(a, b);
  };
}

A variante preguiçosa seria:

function arrayMax(array) {
  var memo = null;
  function actuallyCompute() {
    if(memo === null) {
      memo = array.reduce(function(a, b) {
        return Math.min(a, b);
      });
    }
    return memo;
  }
  return actuallyCompute;
}

O valor retornado é um fechamento que pode ser usado para calcular o valor ou recuperá-lo outra vez, se já tiver sido calculado.

Com esses três exemplos, devemos ter certeza de que os fechamentos e suas aplicações são o núcleo da programação funcional.

Conclusão

Aprender programação funcional significa aprender a programar com fechamentos. Como conseqüência, as linguagens que permitem a fácil manipulação de fechamentos, e principalmente a aplicação parcial de funções, devem ser consideradas ao procurar uma linguagem para estudar programação funcional. Por outro lado, idiomas onde os fechamentos não podem ser facilmente manipulados seriam más escolhas.


11
Obrigado por esta boa amostra. BTW, como você define var info, não seria journal.forEach (info)?
ejaenv

Sim, seria uma variante apropriada! :)
Michael Le Barbier Grünewald 8/15

1

Eu acho que as ferramentas que você usa influenciam muito seu aprendizado. É quase impossível aprender conceitos de programação para os quais a linguagem de programação usada não fornece os meios para fazer uso. Claro, você sempre pode aprender algumas coisas, mas não pode aprender corretamente.

Mas isso é de qualquer maneira acadêmica, porque, como Martinho diz em seu comentário , mesmo se você poderia aprender programação funcional, você deve não tentar fazer isso, porque existem línguas onde este é muito mais fácil.


1

Você não deve aprender programação funcional em C, mas em uma linguagem funcional estrita (Haskell, Caml, Erlang, etc.).

Se você é novo no funcional, nunca o receberá com uma linguagem não funcional. Provavelmente, você se treinará para fazer o que considera programação funcional e aprender as coisas da maneira errada. E é sempre mais difícil "reaprender" as coisas da maneira certa do que aprendê-las da maneira certa no começo.

Enfim, acho que fazer funcional em C é um bom exercício para alguém que já conhece funcional. Porque essa pessoa aprenderá o que está acontecendo por trás do capô - o que o computador está realmente fazendo.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.