Funciones de primera clase

11

Comencé a mirar seriamente a Lisp este fin de semana (con lo que quiero decir que solo he estado aprendiendo Lisp y no volviendo a los proyectos en C #) y debo decir que me encanta. He incursionado en otros lenguajes funcionales (F #, Haskell, Erlang) pero no he sentido el atractivo que me ha dado Lisp.

Ahora, mientras continúo aprendiendo Lisp, comencé a preguntarme por qué los lenguajes no funcionales no admiten funciones de primera clase. Sé que lenguajes como C # pueden hacer cosas similares con los delegados y, en cierta medida, puede usar punteros para funciones en C / C ++, pero ¿hay alguna razón por la que esto nunca se convierta en una característica en esos idiomas? ¿Hay algún inconveniente en hacer que las funciones sean de primera clase? Para mí, es extremadamente útil, así que estoy perdido en cuanto a por qué más lenguajes (fuera del paradigma funcional) no lo implementan.

[Editar] Agradezco las respuestas hasta ahora. Como se me ha demostrado que muchos idiomas ahora admiten funciones de primera clase, volveré a formular la pregunta de por qué los idiomas tardarían tanto en implementarlos. [/Editar]

Jetti
fuente
3
No estoy de acuerdo con que C # pueda hacer "cosas similares". Yo diría que tiene funciones de primera clase para todos los efectos (lo que arruina su premisa). Tiene una sintaxis para los literales de función, puede insertar funciones en variables, etc.
Logan Capaldo
@Logan: estaba debatiendo si incluir ejemplos de C # pero decidí basarme en esta entrada de wikipedia . Según la entrada, no hay verdaderas funciones de primera clase ya que "ya que los objetos que contienen el estado dinámico de la función deben construirse manualmente". Sin embargo, si esa es una declaración incorrecta, ¡me encantaría saber por qué! (¡Después de todo, estoy aquí para aprender y no
quedarme
2
esa entrada de wikipedia está desactualizada. Un C # moderno proporciona una lambda adecuada.
SK-logic
Creo que ese párrafo está mal escrito. Parece estar diciendo que los functores de C ++ no son de primera clase, ¿y tampoco lo son los delegados de C #? Si bien podría estar de acuerdo con el argumento a favor de los functors, no estoy seguro de que lo haría con los delegados de C #. También dice "(ver levantamiento lambda)", que es una declaración sobre estos lenguajes que admiten cierres léxicos en lugar de "funciones como valores". Puedes tener uno sin el otro. Incluso si ese es el caso, no es cierto para C #, tiene cierres léxicos. Parte del problema es que "función de primera clase" puede ser un término vago.
Logan Capaldo
1
@Logan & SK-Logic: agradezco sus comentarios y me mantengo constructivo. Todavía estoy aprendiendo y es muy agradable no ser criticado, así que lo agradezco. Muchas gracias por los comentarios y respuestas!
Jetti

Respuestas:

5

C #, VB.NET, Python, JavaScript, ahora incluso C ++ 0x proporciona funciones de primera clase.

Actualizar:

Una implementación de cierres requiere el levantamiento de lambda, una técnica originalmente bastante extraña para los programadores imperativos. Las funciones de primera clase adecuadas (que incluyen cierres) requieren al menos algo de soporte del tiempo de ejecución y VM. También tomó algún tiempo adoptar las viejas técnicas funcionales en el mundo imperativo.

Y, la parte más importante: las funciones de primera clase son apenas utilizables si no hay recolección de basura presente. Se introdujo en una programación masiva recientemente, con Java y, en consecuencia, .NET. Y el enfoque original de Java fue simplificar en exceso el lenguaje para que los codificadores promedio lo puedan comprender. .NET primero siguió, y solo recientemente se separó de esa dirección (en mi humilde opinión, bastante justificada y apropiada).

Todos estos conceptos tardan en ser digeridos por la industria.

SK-logic
fuente
He editado la pregunta original basada en las respuestas.
Jetti
Funciones de primera clase! = Cierres (y GC es mucho más necesario para este último). Aunque sí, están estrechamente relacionados y rara vez, si es que alguna vez, los ves separados.
@delnan, sin al menos alguna forma de cierres léxicos, las funciones no son componibles ni construibles en tiempo de ejecución, lo cual es obligatorio para una definición de funciones de primera clase.
SK-logic
No. Podría no permitir referirse a variables de ámbitos de cobertura (o copiar los valores de la variable referida en el momento de la creación de la función; no sé si esto cuenta como cierre). El resultado no es particularmente útil, pero las funciones aún se pueden construir en tiempo de ejecución sin ser cierres y, por lo tanto, tendría funciones de primera clase (extrañas).
1
@ SK-logic: C ++ 0x proporciona cierres sin recolección de basura con el truco habitual -> si la variable se sale del alcance y todavía se está aferrando a una referencia, el uso de la referencia es un comportamiento indefinido. Entonces es posible ... simplemente pone el honor en el desarrollador.
Matthieu M.
5

Las funciones de primera clase son mucho menos interesantes sin cierres.

Los cierres no son realmente posibles sin algún tipo de gestión dinámica del alcance (recolección de basura). Una de las cosas que hace que C / C ++ tenga un alto rendimiento es el hecho de que es mucho más fácil compilar un lenguaje en el que administras la memoria manualmente, de modo que de alguna manera se elimina C / C ++ de la ecuación.

Y luego sí, está el asunto del impacto de la POO. Ya no tiene una separación de métodos y propiedades. Los métodos son en sí mismos propiedades que aceptan funciones como valores. En ese contexto, ¿qué significa realmente sobrecargar los métodos, ya que puede cambiar las cosas tontas en cualquier momento? ¿Puede realmente agregar eso a Java, por ejemplo, sin introducir un cambio de paradigma importante en todo el lenguaje? ¿Dónde está el contrato o esa sensación de seguridad (IMO falsa) que las personas obtienen al saber que la construcción garantiza que siempre funcionará de la misma manera cada vez? Puede tener sentido tratar las funciones vinculadas a los objetos como métodos como un organismo diferente en lenguajes que permiten que las funciones existan independientemente en primer lugar, pero en Java eso no es realmente una opción.

En JavaScript, OOP y funcional están muy entrelazados y personalmente me resultaría difícil ver los funcs de primera clase como algo más que atornillado en idiomas donde no lo estaban. Pero eso requiere una serie de otros cambios de cambio de paradigma, incluidos los altos niveles de mutabilidad en los objetos y sus propios métodos, así como la capacidad de invocar funciones como si fueran miembros de cualquier objeto sobre la marcha.

Los idiomas no son solo conjuntos de herramientas llenas de trucos para hacer las cosas en su mayor parte. Son paradigmas. Paquetes de ideas, estrategias y opiniones que todo tipo de cosas van juntas de una manera que está conectada (o parece estar conectada). En muchos casos, las funciones como sustantivo y verbo realmente no se ajustan al paradigma en absoluto o, en el mejor de los casos, son un ajuste imperfecto.

Dicho esto, siento que me falta un brazo cuando me veo obligado a codificar sin ellos.

Erik Reppen
fuente
Puede tratar todos los métodos como sellados o simplemente sellar los que más le interesan, y estará bien.
Alexei Averchenko
@AlexeiAverchenko Estoy encantado de decir que no estoy 100% seguro de lo que quieres decir con eso. Lo siento, me perdí tu comentario hasta ahora. Buscar en Google "métodos sellados".
Erik Reppen
4

No es realmente imposible. Pero es otra característica más, y el presupuesto de complejidad es limitado. El diseñador del lenguaje puede considerarlo innecesario (o incluso no se le ocurre): "¿por qué diablos necesitaríamos pasar funciones? ¡Este lenguaje es para programar un sistema operativo!". También puede tomar un esfuerzo significativo fusionarse con el resto del idioma. Por ejemplo, un tipo de función puede requerir adiciones serias al sistema de tipos (por ejemplo, en Java), aún más si tiene una sobrecarga (gracias @Renesis por señalarlo). También debe proporcionar un código de biblioteca para hacer uso de lo viable: nadie quiere definirse a mapsí mismo.

También podría hacer que otros objetivos del lenguaje sean más difíciles de lograr:

  • Se vuelve "más difícil" optimizar (en realidad no es más difícil en muchos casos, pero requiere enfoques diferentes a los que está acostumbrado). Por ejemplo, si las funciones globales pueden reasignarse, debe probar que fnunca se reasignan antes de incluirlas.
  • Del mismo modo, si crea objetos con funciones completas, necesita un compilador inteligente y JIT para eliminar la sobrecarga asociada a eso y hacer que las llamadas sean tan eficientes (en cuanto a velocidad y espacio) como enviar argumentos y dirección de retorno y saltar a alguna dirección
  • Como ya se mencionó, es otra característica completa y los primeros pasos para admitir otro paradigma: si desea un lenguaje simple, tal vez no pueda permitirse agregar funciones de primera clase sin lanzar otras cosas (que puede considerar mucho más importantes) afuera.
  • Quizás simplemente no se mezcla bien con el resto del lenguaje. Si diseña el lenguaje para, por ejemplo, ser la mejor encarnación de OOP desde Smalltalk, es posible que desee centrarse en eso en lugar de ofrecer otro paradigma muy diferente. Especialmente si es difícil integrar los dos (ver arriba). Los paradigmas N bien hechos son más agradables de programar que los paradigmas N + 1 mal hechos.

En la misma línea, uno puede preguntarse por qué cualquier lenguaje de programación L1 no tiene la función F del lenguaje muy diferente L2.


fuente
1

Creo que el primer problema es un malentendido de que Orientado a objetos y Funcional no se pueden mezclar. Una lista rápida de lenguajes descritos, al menos por Wikipedia, como ambos: JavaScript , ActionScript , Python , C # , F # .

El segundo problema parece ser una definición de funciones de primera clase : ¿por qué no considera que C # las tenga, por ejemplo?

No soy un experto en lenguaje funcional, así que corríjame en los comentarios si me equivoco, pero entiendo que la inclusión de funciones de primera clase en sí misma define más o menos si un lenguaje admite un paradigma funcional .

¿Cuál es la verdadera pregunta?

Entonces, entendiendo que los lenguajes orientados a objetos también pueden ser funcionales, y estos lenguajes contienen funciones de primera clase, parece que la pregunta que está buscando es ¿por qué algunos lenguajes orientados a objetos no contienen funciones de primera clase?

Función de sobrecarga

Una de las razones principales para esto es la dificultad de definir funciones de primera clase cuando el lenguaje también ha elegido soportar la sobrecarga de funciones (ejemplo en Java):

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

¿A qué dispatchEventfunción se referiría una variable?

Programación basada en clase

La programación basada en clases no impide que un lenguaje admita objetos de primera clase, pero puede hacerlo más confuso o agregar preguntas para ser respondidas.

ActionScript, por ejemplo, como lenguaje ECMAScript comenzó en un paradigma mucho más funcional como JavaScript. Las funciones no estaban inherentemente vinculadas a los objetos, esencialmente podían llamarse con cualquier objeto, ya que su alcance en el momento de la ejecución.

Cuando agrega clases (no dinámicas), tiene funciones que están inherentemente vinculadas a una instancia, no solo a la clase en sí. Esto arroja algunas arrugas en la especificación de Function.applyque honestamente no he profundizado para descubrir cómo lo han tratado.

Nicole
fuente
3
"La inclusión de funciones de primera clase más o menos hace que un lenguaje sea funcional". - Incorrecto. Es un requisito previo, sí. Pero hay mucho más, como (por nombrar solo tres) evitar el estado mutable, el enfoque en las expresiones y la aplicación de funciones en lugar de declaraciones secuenciales y el énfasis en la transparencia referencial.
@delnan Deberías ir a Wikipedia correcto entonces ... A menos que un "lenguaje funcional" y un "lenguaje que soporte un paradigma funcional" sean dos cosas diferentes.
Nicole
1
@Rensis: Son cosas diferentes. Puedes crear algo como objetos (incluso incluyendo vtables) en C, pero no es bonito. Pasar de "tiene funciones de primera clase" a "es un lenguaje funcional" no es tan malo, pero sigue siendo una diferencia. Además, wiki (correctamente) establece en la página a la que enlazó "Estas características son necesarias para el estilo de programación funcional [...]". (es decir: no es "la característica definitoria") y enumera varias otras características en la página en FP.
@delnan, está bien, corrigí mi redacción. Solo quise decir la condición para que un idioma sea considerado como compatible con un paradigma funcional, al igual que la página de Wikipedia para cada uno de los idiomas que enumeré. No quise decir que eso es todo lo que forma parte del estilo de programación funcional .
Nicole
0

Me he preguntado lo mismo. Una vez que estoy en un idioma con lambdas, los uso MUCHO. Incluso PHP mejora cuando te das cuenta de que puedes hacer un cierre con php 5.3 (no es tan bueno como lisp, pero aún mejor)

Zachary K
fuente