¿Puedes aprender programación funcional en C? [cerrado]

9

Como resultado de la discusión de comentarios aquí , me pregunto si puede aprender la programación funcional en C?

sbi
fuente
30
En cuanto a si puedes o no puedes, no deberías .
R. Martinho Fernandes
27
¡Absolutamente! El primer paso es escribir un intérprete Lisp ;-)
Ferruccio
Si lo entendí bien, la pregunta debería haber sido sobre aprender varios conceptos con pseudocódigo, sin ningún lenguaje real.
SK-logic
@ SK-logic: Para decirlo suavemente, muy pocos programadores han aprendido a programar únicamente con pseudocódigo, la mayoría tuvo que ensuciarse las manos y golpearse la cara con mensajes de error del compilador / intérprete.
sbi
44
@sbi, algunos de los mejores programadores han aprendido programación cuando los compiladores no tenían ningún mensaje de error. La codificación en tarjetas perforadas requiere un poco de comprensión de lo que está haciendo mucho antes de que tenga la oportunidad de ejecutar el código. Y no hace falta mencionar que la base para la programación funcional se había establecido mucho antes de que se construyera una primera computadora.
SK-logic

Respuestas:

21

Obviamente, puedes hacer programación funcional en C. En teoría, también puedes aprender principios de programación funcional en C, pero el lenguaje no lo hace fácil.

Supongo que tiene al menos un poco de experiencia en OOP; si lo hace, debe tener en cuenta que la POO se puede hacer en C, incluido el polimorfismo, captadores / establecedores, reglas de visibilidad, etc., etc., pero es bastante doloroso hacerlo, y necesita saber tanto POO como C en el interior fuera para lograrlo. Es lo mismo con FP.

Lo que debería hacer es aprender primero un lenguaje de programación funcional (la mayoría de ellos tienen reglas de sintaxis sorprendentemente simples; no es la sintaxis lo que los hace difíciles de aprender), y luego dejar que su sabiduría recién adquirida influya en la forma en que escribe C.


Según la solicitud, algunas cosas que puede aprender de FP y luego aplicar en, por ejemplo, C, C ++ o Java:

  • Evitar estado, especialmente estado mutable compartido
  • Apreciar funciones puras
  • Apreciar la evaluación perezosa
  • Ser capaz de modelar en términos de verbos en lugar de sustantivos
  • Ser capaz de abordar los problemas de forma recursiva e iterativa
  • Usar funciones de orden superior
  • Pensando en las funciones como otro tipo de valor, que puede pasar y combinar con otros valores
  • Usar funciones de primera clase como alternativa para el polimorfismo basado en objetos.
tdammers
fuente
1
¿Puede proporcionar ejemplos específicos de cómo los programadores de C / C ++ / Java pueden beneficiarse de la sabiduría de LISP? Tiene sentido en teoría, pero estoy buscando algo concreto.
Trabajo
@ Job, ¿Qué beneficio concreto puede haber? Expande sus mentes y tal vez los hace pensar en un estado mutable excesivo como algo malo, ¿qué más se puede pedir?
dan_waterworth
Entonces, ¿puedo concluir de esto que, si bien es posible aprender (algunos) FP en C, no tiene sentido hacerlo?
sbi
@ Job: aprendí FP cuando aprendí LISP como estudiante hace muchos años. Aproximadamente una década después apliqué FP en la metaprogramación de plantillas.
sbi
1
@sbi, mi forma favorita de aprender nuevos idiomas y conceptos es a través de su implementación. Y C es un lenguaje bastante decente para implementar un compilador. Entonces, sí, puedes aprender FP con C.
SK-logic
11

C puede ser pirateado para ofrecer algunos conceptos funcionales:

Esta pregunta de StackOverflow le dará más información. Pero aunque parece posible hacer una programación funcional (o un gran subconjunto de) en C, los hacks y las extensiones del compilador y lo que sea no son la mejor manera de aprender un concepto.

Para aprender realmente la programación funcional, su mejor opción es uno de los lenguajes de programación funcional prominentes como Lisp y sus dialectos ( Clojure , Scheme ), Erlang y Haskell . Cualquiera de esas son herramientas perfectas que funcionan dentro de la mentalidad de programación funcional. F # también es un buen candidato si tiene experiencia en .Net, pero es un lenguaje de paradigmas múltiples, no estrictamente un lenguaje de programación funcional.


Como señala Tdammers en los comentarios:

En realidad, LISP, clojure y el esquema también son multi-paradigmáticos; Haskell, aunque es puro y vago por defecto, también permite la programación imperativa en un contexto monádico, y tiene un amplio soporte para el procesamiento concurrente. Todos estos tienen mecanismos que implementan grandes partes de la sabiduría reunida en el mundo OOP: encapsulación, herencia, responsabilidad única, composición, etc. No se trata tanto de si un lenguaje PERMITE otros paradigmas; se trata de qué paradigma forma el punto de partida de un lenguaje.

Que yo sepa, Lisp y sus dialectos y Erlang son mejores candidatos que F # porque fomentan la programación funcional sobre otros paradigmas, lo que Tdammers afirma maravillosamente como punto de partida de un lenguaje . F # abarca la programación funcional pero no la alienta sobre sus otros paradigmas compatibles, programación imperativa y oo.

Yannis
fuente
Con respecto a su última oración: en ese caso, argumentaría que F # es un mejor candidato porque no lo atrapará en una mentalidad funcional. En un lenguaje de paradigmas múltiples, cuando comienzas a martillar tornillos, puedes cambiar a un destornillador. Cuando está atrapado en un solo paradigma, puede pasar por alto la diferencia entre el tornillo y el clavo.
R. Martinho Fernandes
Bueno, la pregunta es cómo aprender programación funcional, no programación. Supongo que el operador tiene cierta experiencia en un lenguaje de paradigmas múltiples y quiere la forma más eficiente de aprender programación funcional, en cuyo caso F # es un buen candidato pero no perfecto. Atrapado en un solo paradigma es obviamente la mejor manera cuando se busca aprender ese paradigma único, ya que no tiene que lidiar con todo lo que no es.
Yannis
Creo que aprender cuando el paradigma es adecuado y cuando no lo es para una determinada tarea es parte del aprendizaje, quizás lo más importante.
R. Martinho Fernandes
44
En realidad, LISP, clojure y el esquema también son multi-paradigmáticos; Haskell, si bien es puro y vago por defecto, también permite la programación imperativa en un contexto monádico, y tiene un amplio soporte para el procesamiento concurrente. Todos estos tienen mecanismos que implementan grandes partes de la sabiduría reunida en el mundo OOP: encapsulación, herencia, responsabilidad única, composición, etc. No se trata tanto de si un lenguaje PERMITE otros paradigmas; se trata de qué paradigma forma el punto de partida de un lenguaje.
tdammers
2
@MartinhoFernandes: Uno podría argumentar que estar atrapado en un solo paradigma es la manera perfecta de aprender cuando realmente es un dolor de cabeza :-)
Jörg W Mittag
2

No puede aprender todos los aspectos de la programación funcional en C. Pero seguramente puede comenzar la programación de estilo funcional con cualquier lenguaje imperativo. Estos bits iniciales son: "Cómo mantener las cosas puras mientras se programa". Y se puede hacer C también. Consulte esta publicación de blog para obtener más detalles.

http://www.johndcook.com/blog/2011/07/24/get-started-functional-programming/

Gulshan
fuente
2

TL; DR

La programación funcional se trata de cierres y sus aplicaciones. A menos que alguien pueda mostrarle una biblioteca de cierre de descenso para C, olvídese de usar C para aprender programación funcional.

¿Qué es la programación funcional?

El concepto fundamental de la programación funcional es la noción de cierres que, en términos generales, captura una función junto con enlaces de variables. Además del uso generalizado de los cierres, existen algunos otros rasgos distintivos en la programación funcional, como el uso de funciones recursivas y valores inmutables (ambos juegan bien juntos). Estos rasgos son más un problema cultural que cualquier otra cosa, y no hay ninguna obstrucción técnica para usarlos en prácticamente cualquier idioma, es por eso que me concentro en los cierres en mi respuesta: no todos los idiomas permiten crear cierres fácilmente.

Tres ilustraciones de la utilidad de los cierres.

Un uso típico de los cierres es la implementación de mecanismos de privacidad. Por ejemplo, el código Javascript: en los ejemplos elegí Javascript porque es un lenguaje funcional con una llamada "sintaxis tipo C" y su pregunta sugiere que está familiarizado con C:

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

Luego con

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

Tenemos dos funciones ay bcontando colecciones disjuntas. El punto del ejemplo es que las variables xson capturadas por el cierre que define el countercierre y cada vez que hay un nuevo countercierre is instantiated by the function, it gets its fresh own idea of whatx`.

Otro uso típico de los cierres es la definición de aplicaciones parciales de funciones. Suponga que tenemos un servicio de informes similar a la syslogimplementación de una función

var log = function(priority, message) {

};

donde los argumentos priorityy messagese espera que sean cadenas, siendo el primero uno de "debug", "info"y así sucesivamente. Podemos definir una fábrica de registros como esta:

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

y úselo para definir versiones especializadas de nuestra instalación de registro:

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

Esto es muy útil, porque en lugar de escribir forbucles propensos a errores como este

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

podemos escribir el más limpio, más corto y mucho más simple (no hay i, eso es mucho mejor):

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

Un tercer campo de aplicación importante de los cierres es la implementación de la evaluación diferida: tenga en cuenta que el soporte de lenguaje especial puede proporcionar una mejor implementación.

Una función perezosa, en lugar de realizar un cálculo directo, devuelve un cierre que se puede llamar (o "forzar" en la jerga de la pereza) para realizar la pregunta. La motivación para hacer esto es que separa la preparación de un cálculo y la realización de un cálculo. Un ejemplo práctico de esto es la compilación de expresiones regulares: si un programa compila muchas expresiones regulares en el momento del inicio, necesitará mucho tiempo para comenzar. Si en cambio compilamos perezosamente las expresiones regulares y las forzamos a medida que las necesitamos, entonces nuestro programa puede comenzar rápidamente. Por supuesto, las expresiones regulares pueden sustituirse aquí con cualquier estructura que requiera un tiempo de inicialización considerable.

Aquí se explica cómo implementar una evaluación diferida con cierres. Considere la implementación clásica de la función arrayMax que devuelve el máximo en una matriz:

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

La variante perezosa sería:

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;
}

El valor devuelto es un cierre que se puede usar para calcular el valor o recuperarlo en otro momento si ya se ha calculado.

Con estos tres ejemplos, debemos estar seguros de que los cierres y sus aplicaciones son el núcleo de la programación funcional.

Conclusión

Aprender programación funcional significa aprender a programar con cierres. Como consecuencia, los lenguajes que permiten la fácil manipulación de los cierres, y especialmente la aplicación parcial de funciones, deben considerarse al buscar un lenguaje para estudiar la programación funcional. Por el contrario, los idiomas donde los cierres no pueden ser fácilmente manipulados serían malas elecciones.

Michael Le Barbier Grünewald
fuente
1
Gracias por esta buena muestra. Por cierto, al definir la información de var, ¿no sería journal.forEach (info)?
ejaenv
¡Sí, sería una variante apropiada! :)
Michael Le Barbier Grünewald
1

Creo que las herramientas que utilizas influyen mucho en tu aprendizaje. Es casi imposible aprender conceptos de programación para los cuales el lenguaje de programación que utiliza no proporciona los medios para utilizarlo. Claro, siempre puedes aprender algunas cosas, pero no puedes aprenderlas correctamente.

Pero eso es académico de todos modos, porque, como Martinho dice en su comentario , incluso si pudieras aprender programación funcional, no deberías intentar hacerlo, porque hay lenguajes donde esto es mucho más fácil.

sbi
fuente
1

No debe aprender programación funcional en C, sino en un lenguaje funcional estricto (Haskell, Caml, Erlang, etc.).

Si eres nuevo en funcional, nunca lo conseguirás realmente con un lenguaje no funcional. Lo más probable es que te entrenes para hacer lo que crees que es programación funcional y aprender las cosas de manera incorrecta. Y siempre es más difícil "volver a aprender" las cosas de la manera correcta que aprenderlas de la manera correcta al principio.

De todos modos, creo que hacer funcional en C es un buen ejercicio para alguien que ya sabe funcional. Porque esa persona aprenderá lo que sucede detrás del capó, lo que realmente está haciendo la computadora.

deadalnix
fuente