¿Por qué la mayoría de los lenguajes de programación tienen palabras clave o sintaxis especiales para declarar funciones? [cerrado]

39

La mayoría de los lenguajes de programación (lenguajes de tipo dinámico y estático) tienen palabras clave y / o sintaxis especiales que se ven muy diferentes a las variables de declaración para funciones de declaración. Veo funciones tan solo como declarar otra entidad con nombre:

Por ejemplo en Python:

x = 2
y = addOne(x)
def addOne(number): 
  return number + 1

Por qué no:

x = 2
y = addOne(x)
addOne = (number) => 
  return number + 1

Del mismo modo, en un lenguaje como Java:

int x = 2;
int y = addOne(x);

int addOne(int x) {
  return x + 1;
}

Por qué no:

int x = 2;
int y = addOne(x);
(int => int) addOne = (x) => {
  return x + 1;
}

Esta sintaxis parece una forma más natural de declarar algo (ya sea una función o una variable) y una palabra clave menos como defo functionen algunos idiomas. Y, en mi opinión, es más consistente (busco en el mismo lugar para comprender el tipo de una variable o función) y probablemente hace que el analizador / gramática sea un poco más simple de escribir.

Sé que muy pocos lenguajes utilizan esta idea (CoffeeScript, Haskell) pero los lenguajes más comunes tienen una sintaxis especial para funciones (Java, C ++, Python, JavaScript, C #, PHP, Ruby).

Incluso en Scala, que admite ambas formas (y tiene inferencia de tipos), es más común escribir:

def addOne(x: Int) = x + 1

Más bien que:

val addOne = (x: Int) => x + 1

OMI, al menos en Scala, esta es probablemente la versión más fácil de entender, pero este modismo rara vez se sigue:

val x: Int = 1
val y: Int = addOne(x)
val addOne: (Int => Int) = x => x + 1

Estoy trabajando en mi propio lenguaje de juguetes y me pregunto si hay algún inconveniente si diseño mi lenguaje de tal manera y si hay alguna razón histórica o técnica por la que este patrón no se sigue ampliamente.

pathikrit
fuente
9
La razón es probablemente histórica. Quien lo hizo primero lo hizo de esa manera, y todos los demás lo copiaron. Pero dudo que podamos saberlo con certeza.
29
Creo que es porque una función o método simplemente no es simplemente otra entidad con nombre . En lenguajes funcionales, son (puede pasarlos, etc.) pero en otros lenguajes (como Java) una función o método es algo completamente diferente de una variable simple y no puede tratarse como tal (admito que Java 8 debilita esto ), por lo que tiene sentido definir funciones / métodos de manera diferente, ya que se comportan de manera diferente.
11684
15
No estoy de acuerdo con que su propuesta sea una forma más natural de declarar funciones. Realmente no me gusta la sintaxis de Coffeescript y parte de eso tiene que ver con su sintaxis de declaración de función. El hecho es que si no está roto, no lo arregles. Escribir 'def' o 'function' no es gran cosa y es mucho más obvio que una mirada en comparación con algunos símbolos elegantes de Perl que con ojos irreflexivos o cansados ​​podrían confundirse fácilmente con otra cosa. En una nota completamente personal, también creo que la sintaxis sugerida en los ejemplos se ve mucho más fea que la sintaxis actual.
Roy
22
¿Cómo es '=>' no es una "palabra clave o sintaxis especial? para declarar una función"?
TML
11
No sé sobre ti, pero para mí (int => int) addOne = (x) => {es mucho más "especial" y "complejo" que int addOne(int) {...
Bogdan Alexandru

Respuestas:

48

Creo que la razón es que los lenguajes más populares provienen o fueron influenciados por la familia de lenguajes C en lugar de lenguajes funcionales y su raíz, el cálculo lambda.

Y en estos idiomas, las funciones no son solo otro valor:

  • En C ++, C # y Java, puede sobrecargar funciones: puede tener dos funciones con el mismo nombre, pero con una firma diferente.
  • En C, C ++, C # y Java, puede tener valores que representan funciones, pero los punteros de función, functores, delegados e interfaces funcionales son distintos de las funciones mismas. Parte de la razón es que la mayoría de ellas no son solo funciones, sino que son una función junto con algún estado (mutable).
  • Las variables son mutables por defecto (debe usar const , readonlyo finalpara prohibir mutación), pero las funciones no pueden ser reasignados.
  • Desde una perspectiva más técnica, el código (que se compone de funciones) y los datos están separados. Por lo general, ocupan diferentes partes de la memoria, y se accede a ellas de manera diferente: el código se carga una vez y luego solo se ejecuta (pero no se lee ni se escribe), mientras que los datos a menudo se asignan y desasignan constantemente y se escriben y leen, pero nunca se ejecutan.

    Y dado que C estaba destinado a estar "cerca del metal", tiene sentido reflejar esta distinción en la sintaxis del lenguaje también.

  • El enfoque de "función es solo un valor" que forma la base de la programación funcional ha ganado fuerza en los lenguajes comunes solo relativamente recientemente, como lo demuestra la introducción tardía de lambdas en C ++, C # y Java (2011, 2007, 2014).

svick
fuente
12
C # tenía funciones anónimas, que son solo lambdas sin inferencia de tipos y una sintaxis torpe, desde 2005.
Eric Lippert
2
"Desde una perspectiva más técnica, el código (que está compuesto de funciones) y los datos están separados", algunos idiomas, más bien a sabiendas, los LISP no hacen esa separación y realmente no tratan el código y los datos de manera muy diferente. (Los LISP son el ejemplo más conocido, pero hay muchos otros idiomas como REBOL que hacen esto)
Benjamin Gruenbaum
1
@BenjaminGruenbaum Estaba hablando del código compilado en la memoria, no del nivel del idioma.
svick
C tiene punteros de función que, al menos levemente, pueden considerarse simplemente como otro valor. Un valor peligroso para meterse con seguridad, pero han sucedido cosas más extrañas.
Patrick Hughes
@PatrickHughes Sí, los menciono en mi segundo punto. Pero los punteros de función son bastante diferentes de las funciones.
svick
59

Es porque es importante que los humanos reconozcan que las funciones no son solo "otra entidad con nombre". A veces tiene sentido manipularlos como tales, pero aún pueden reconocerse de un vistazo.

Realmente no importa lo que la computadora piense acerca de la sintaxis, ya que un bloque de caracteres incomprensible está bien para que una máquina lo interprete, pero eso sería casi imposible de entender y mantener para los humanos.

Realmente es la misma razón por la que tenemos bucles while y for, switch y, de lo contrario, etc., aunque todos finalmente se reducen a una instrucción de comparación y salto. La razón es porque está ahí para el beneficio de los humanos que mantienen y entienden el código.

Tener sus funciones como "otra entidad con nombre" de la manera que está proponiendo hará que su código sea más difícil de ver y, por lo tanto, más difícil de entender.

como se llame
fuente
12
No estoy de acuerdo con que tratar las funciones como entidades con nombre necesariamente haga que el código sea más difícil de entender. Eso es casi cierto para cualquier código que siga un paradigma de procedimiento, pero puede no ser cierto para el código que sigue un paradigma funcional.
Kyle Strand
29
"Realmente es la misma razón por la que tenemos bucles while y for, switch y, de lo contrario, etc., a pesar de que todos finalmente se reducen a una instrucción de comparación y salto ". Si todos los programadores se sintieran cómodos con el lenguaje de máquina, no necesitaríamos todos estos sofisticados lenguajes de programación (nivel alto o bajo). Pero la verdad es que todos tienen un nivel de comodidad diferente en cuanto a qué tan cerca de la máquina quieren escribir su código. Una vez que encuentre su nivel, solo tiene que seguir con la sintaxis que se le proporcionó (o escribir sus propias especificaciones de idioma y compilador si realmente le molesta).
Hoki
12
+1. Una versión más concisa podría ser "¿Por qué todos los lenguajes naturales distinguen los sustantivos de los verbos?"
msw
2
"una máquina incomprensible de caracteres está bien para que una máquina la interprete, pero eso sería casi imposible de entender y mantener para los humanos" Qué calificación tan imprudente para un cambio sintáctico tan modesto como se propone en la pregunta. Uno se adapta rápidamente a la sintaxis. Esta propuesta es una desviación mucho menos radical de la convención que el método OO llamado sintaxis object.method (args) fue en su momento, sin embargo, este último no ha demostrado ser casi imposible de entender y mantener para los humanos. A pesar del hecho de que en la mayoría de los lenguajes OO, los métodos no deben considerarse almacenados en instancias de clase.
Marc van Leeuwen
44
@MarcvanLeeuwen. Su comentario es verdadero y tiene sentido, pero se genera cierta confusión por la forma en que se redacta la publicación original. En realidad hay 2 preguntas: (i) ¿Por qué es así? y (ii) ¿Por qué no de esta manera? . La respuesta whatsisnamefue más abordar el primer punto (y alertar sobre algún peligro de eliminar estos a prueba de fallas), mientras que su comentario está más relacionado con la segunda parte de la pregunta. De hecho, es posible cambiar esta sintaxis (y como usted describió, ya se ha hecho muchas veces ...) pero no se adaptará a todos (ya que oop tampoco se adapta a todos.)
Hoki
10

Quizás le interese saber que, en tiempos prehistóricos, un lenguaje llamado ALGOL 68 usaba una sintaxis cercana a la que usted propone. Reconociendo que los identificadores de función están vinculados a valores al igual que otros identificadores, podría en ese lenguaje declarar una función (constante) utilizando la sintaxis

nombre de tipo de función = ( lista de parámetros ) tipo de resultado : cuerpo ;

Concretamente tu ejemplo leería

PROC (INT)INT add one = (INT n) INT: n+1;

Reconociendo la redundancia en que el tipo inicial puede leerse desde el RHS de la declaración, y al ser un tipo de función siempre comienza PROC, esto podría (y generalmente sería) contratado

PROC add one = (INT n) INT: n+1;

pero tenga en cuenta que =todavía aparece antes de la lista de parámetros. También tenga en cuenta que si desea una variable de función (a la que luego se le podría asignar otro valor del mismo tipo de función), =debe reemplazarse por :=, dando cualquiera de

PROC (INT)INT func var := (INT n) INT: n+1;
PROC func var := (INT n) INT: n+1;

Sin embargo, en este caso ambas formas son, de hecho, abreviaturas; Como el identificador func vardesigna una referencia a una función generada localmente, la forma completamente expandida sería

REF PROC (INT)INT func var = LOC PROC (INT)INT := (INT n) INT: n+1;

Es fácil acostumbrarse a esta forma sintáctica particular, pero claramente no tenía muchos seguidores en otros lenguajes de programación. Incluso los lenguajes de programación funcionales como Haskell prefieren el estilo f n = n+1con la = siguiente lista de parámetros. Supongo que la razón es principalmente psicológica; después de todo, incluso los matemáticos no suelen preferir, como yo, f = nn + 1 sobre f ( n ) = n + 1.

Por cierto, la discusión anterior resalta una diferencia importante entre las variables y las funciones: las definiciones de funciones generalmente vinculan un nombre a un valor de función específico, que no se puede cambiar más tarde, mientras que las definiciones de variables generalmente introducen un identificador con un valor inicial , pero uno que Puede cambiar más tarde. (No es una regla absoluta; las variables de función y las constantes que no son de función se producen en la mayoría de los idiomas). Además, en los lenguajes compilados, el valor vinculado en una definición de función suele ser una constante de tiempo de compilación, por lo que las llamadas a la función pueden ser compilado usando una dirección fija en el código. En C / C ++ esto es incluso un requisito; el equivalente del ALGOL 68

PROC (REAL) REAL f = IF mood=sunny THEN sin ELSE cos FI;

no se puede escribir en C ++ sin introducir un puntero de función. Este tipo de limitaciones específicas justifican el uso de una sintaxis diferente para las definiciones de funciones. Pero dependen de la semántica del lenguaje, y la justificación no se aplica a todos los idiomas.

Marc van Leeuwen
fuente
1
"Los matemáticos no prefieren f = nn + 1 sobre f ( n ) = n + 1" ... Por no hablar de los físicos, los que les gusta escribir solamente f = n + 1 ...
leftaroundabout
1
@leftaroundabout eso es porque ⟼ es un dolor de escribir. Honestamente.
Pierre Arlaud
8

Mencionaste Java y Scala como ejemplos. Sin embargo, pasó por alto un hecho importante: esas no son funciones, son métodos. Los métodos y funciones son fundamentalmente diferentes. Las funciones son objetos, los métodos pertenecen a los objetos.

En Scala, que tiene funciones y métodos, existen las siguientes diferencias entre métodos y funciones:

  • los métodos pueden ser genéricos, las funciones no pueden
  • los métodos no pueden tener una, una o varias listas de parámetros, las funciones siempre tienen exactamente una lista de parámetros
  • los métodos pueden tener una lista de parámetros implícita, las funciones no pueden
  • los métodos pueden tener parámetros opcionales con argumentos predeterminados, las funciones no pueden
  • los métodos pueden tener parámetros repetidos, las funciones no pueden
  • los métodos pueden tener parámetros de nombre, las funciones no pueden
  • los métodos se pueden llamar con argumentos con nombre, las funciones no se pueden
  • las funciones son objetos, los métodos no

Por lo tanto, su reemplazo propuesto simplemente no funciona, al menos para esos casos.

Jörg W Mittag
fuente
2
"Las funciones son objetos, los métodos pertenecen a los objetos". ¿Se supone que eso se aplica a todos los lenguajes (como C ++)?
svick
9
"los métodos pueden tener parámetros de nombre, las funciones no pueden": esta no es una diferencia fundamental entre métodos y funciones, es solo una peculiaridad de Scala. Lo mismo con la mayoría (¿todos?) De los demás.
user253751
1
Los métodos son fundamentalmente solo un tipo especial de funciones. -1. Tenga en cuenta que Java (y por extensión Scala) no tiene ningún otro tipo de funciones. Sus "funciones" son objetos con un método (en general, las funciones pueden no ser objetos o incluso valores de primera clase; si son depende del lenguaje).
Jan Hudec
@ JanHudec: Semánticamente, Java tiene funciones y métodos; utiliza la terminología "métodos estáticos" cuando se refiere a funciones, pero dicha terminología no borra la distinción semántica.
supercat
3

Las razones que puedo pensar son:

  • Es más fácil para el compilador saber lo que declaramos.
  • Es importante que sepamos (de manera trivial) si esta es una función o una variable. Las funciones son generalmente cajas negras y no nos importa su implementación interna. No me gusta la inferencia de tipos en los tipos de retorno en Scala, porque creo que es más fácil usar una función que tiene un tipo de retorno: a menudo es la única documentación proporcionada.
  • Y la más importante es la siguiente estrategia de multitud que se utiliza en el diseño de lenguajes de programación. C ++ fue creado para robar programadores en C, y Java fue diseñado de una manera que no asusta a los programadores de C ++, y C # para atraer a los programadores de Java. Incluso C #, que creo que es un lenguaje muy moderno con un equipo increíble detrás, copió algunos errores de Java o incluso de C.
Sleiman Jneidi
fuente
2
"... y C # para atraer a los programadores de Java": esto es cuestionable, C # es mucho más similar a C ++ que Java. y a veces parece que se hizo intencionalmente incompatible con Java (sin comodines, sin clases internas, sin covarianza de tipo de retorno ...)
Sarge Borsch
1
@SargeBorsch No creo que se haya hecho intencionalmente incompatible con Java, estoy bastante seguro de que el equipo de C # simplemente trató de hacerlo bien, o hacerlo mejor, como quiera verlo. Microsoft ya escribió su propio Java y JVM y fue demandado. Entonces, el equipo de C # probablemente estaba muy motivado para eclipsar Java. Seguramente es incompatible, y mejor por ello. Java comenzó con algunas limitaciones básicas y me alegra que el equipo de C # haya elegido, por ejemplo, hacer genéricos de manera diferente (visible en el sistema de tipos y no solo en azúcar).
codenheim
2

Cambiando la pregunta, si uno no está interesado en tratar de editar el código fuente en una máquina que está extremadamente limitada por RAM, o minimizar el tiempo para leerlo en un disquete, ¿qué tiene de malo usar palabras clave?

Ciertamente, es más agradable de leer x=y+zque store the value of y plus z into x, pero eso no significa que los caracteres de puntuación sean inherentemente "mejores" que las palabras clave. Si las variables i, jy kson Integer, y xes Real, considere las siguientes líneas en Pascal:

k := i div j;
x := i/j;

La primera línea realizará una división entera truncada, mientras que la segunda realizará una división de números reales. La distinción se puede hacer muy bien porque Pascal usa divcomo su operador de división de números enteros truncados, en lugar de tratar de usar un signo de puntuación que ya tiene otro propósito (división de números reales).

Si bien hay algunos contextos en los que puede ser útil hacer que una definición de función sea concisa (por ejemplo, una lambda que se usa como parte de otra expresión), generalmente se supone que las funciones se destacan y son fácilmente reconocibles visualmente como funciones. Si bien podría ser posible hacer la distinción mucho más sutil y usar nada más que caracteres de puntuación, ¿cuál sería el punto? Decir Function Foo(A,B: Integer; C: Real): Stringdeja en claro cuál es el nombre de la función, qué parámetros espera y qué devuelve. Tal vez uno podría acortarlo en seis o siete caracteres reemplazándolos Functioncon algunos caracteres de puntuación, pero ¿qué se ganaría?

Otra cosa a tener en cuenta es que en la mayoría de los marcos existe una diferencia fundamental entre una declaración que siempre asociará un nombre con un método particular o un enlace virtual particular, y uno que crea una variable que inicialmente identifica un método o enlace particular, pero podría cambiarse en tiempo de ejecución para identificar a otro. Dado que estos son conceptos semánticamente muy diferentes en la mayoría de los marcos de procedimientos, tiene sentido que tengan una sintaxis diferente.

Super gato
fuente
3
No creo que esta pregunta sea sobre concisión. Especialmente porque, por ejemplo, en void f() {}realidad es más corto que el equivalente lambda en C ++ ( auto f = [](){};), C # ( Action f = () => {};) y Java ( Runnable f = () -> {};). La concisión de lambdas proviene de la inferencia de tipos y la omisión return, pero no creo que eso esté relacionado con lo que plantea esta pregunta.
svick
2

Bueno, la razón podría ser que esos idiomas no son lo suficientemente funcionales, por así decirlo. En otras palabras, rara vez define funciones. Por lo tanto, el uso de una palabra clave adicional es aceptable.

En los idiomas de la herencia ML o Miranda, OTOH, usted define funciones la mayoría de las veces. Mire algún código de Haskell, por ejemplo. Literalmente es principalmente una secuencia de definiciones de funciones, muchas de ellas tienen funciones locales y funciones locales de esas funciones locales. Por lo tanto, una palabra clave divertida en Haskell sería un error tan grande como requerir una declaración de evaluación en un lenguaje imperativo para comenzar con la asignación . La asignación de causa es, con mucho, la declaración más frecuente.

Ingo
fuente
1

Personalmente, no veo ningún defecto fatal en tu idea; puede encontrar que es más complicado de lo que esperaba expresar ciertas cosas usando su nueva sintaxis, y / o puede encontrar que necesita revisarla (agregando varios casos especiales y otras características, etc.), pero dudo que se encuentre necesitando abandonar la idea por completo.

La sintaxis que ha propuesto se parece más o menos a una variante de algunos de los estilos de notación que a veces se utilizan para expresar funciones o tipos de funciones en matemáticas. Esto significa que, como todas las gramáticas, probablemente atraerá más a algunos programadores que a otros. (Como matemático, me gusta).

Sin embargo, debe tener en cuenta que en la mayoría de los idiomas, la defsintaxis de estilo (es decir, la sintaxis tradicional) se comporta de manera diferente a una asignación de variable estándar.

  • En la familia Cy C++, las funciones generalmente no se tratan como "objetos", es decir, fragmentos de datos mecanografiados para copiar y colocar en la pila y otras cosas. (Sí, puede tener punteros de función, pero todavía apuntan a código ejecutable, no a "datos" en el sentido típico).
  • En la mayoría de los lenguajes OO, hay un manejo especial para los métodos (es decir, funciones miembro); es decir, no son solo funciones declaradas dentro del alcance de una definición de clase. La diferencia más importante es que el objeto en el que se llama el método se pasa típicamente como un primer parámetro implícito al método. Python hace esto explícito con self(que, por cierto, no es realmente una palabra clave; podría hacer que cualquier identificador válido sea el primer argumento de un método).

Debe considerar si su nueva sintaxis representa con precisión (y con suerte de forma intuitiva) lo que el compilador o el intérprete realmente está haciendo. Puede ser útil leer, por ejemplo, la diferencia entre lambdas y métodos en Ruby; esto le dará una idea de cómo su paradigma de funciones son solo datos difiere del paradigma típico de OO / procedimiento.

Kyle Strand
fuente
1

Para algunos idiomas, las funciones no son valores. En tal lenguaje para decir que

val f = << i : int  ... >> ;

es una definición de función, mientras que

val a = 1 ;

declara una constante, es confuso porque está usando una sintaxis para significar dos cosas.

Otros lenguajes, como ML, Haskell y Scheme, tratan las funciones como valores de primera clase, pero proporcionan al usuario una sintaxis especial para declarar constantes con valores de función. * Están aplicando la regla que "el uso acorta la forma". Es decir, si una construcción es común y detallada, debe darle al usuario una abreviatura. No es elegante darle al usuario dos sintaxis diferentes que significan exactamente lo mismo; a veces la elegancia debe ser sacrificada por la utilidad.

Si, en su idioma, las funciones son de primera clase, ¿por qué no tratar de encontrar una sintaxis lo suficientemente concisa como para no sentirse tentado a encontrar un azúcar sintáctico?

- Editar -

Otro problema que nadie ha planteado (todavía) es la recursividad. Si usted permite

{ 
    val f = << i : int ... g(i-1) ... >> ;
    val g = << j : int ... f(i-1) ... >> ;
    f(x)
}

y tu permites

{
    val a = 42 ;
    val b = a + 1 ;
    a
} ,

¿se sigue que debes permitir

{
    val a = b + 1 ; 
    val b = a - 1 ;
    a
} ?

En un lenguaje vago (como Haskell), no hay problema aquí. En un lenguaje esencialmente sin controles estáticos (como LISP), no hay ningún problema aquí. Pero en un lenguaje entusiasta revisado estáticamente, debe tener cuidado con la forma en que se definen las reglas de la verificación estática, si desea permitir las dos primeras y prohibir las últimas.

- Fin de la edición -

* Se podría argumentar que Haskell no pertenece a esta lista. Proporciona dos formas de declarar una función, pero ambas son, en cierto sentido, generalizaciones de la sintaxis para declarar constantes de otros tipos.

Theodore Norvell
fuente
0

Esto puede ser útil en lenguajes dinámicos donde el tipo no es tan importante, pero no es tan legible en lenguajes tipados estáticos donde siempre desea saber el tipo de su variable. Además, en lenguajes orientados a objetos es muy importante saber el tipo de su variable, para saber qué operaciones admite.

En su caso, una función con 4 variables sería:

(int, long, double, String => int) addOne = (x, y, z, s) => {
  return x + 1;
}

Cuando miro el encabezado de la función y veo (x, y, z, s) pero no sé los tipos de estas variables. Si quiero saber qué tipo zes el tercer parámetro, tendré que mirar el comienzo de la función y comenzar a contar 1, 2, 3 y luego ver que el tipo es double. De la primera manera miro directamente y veo double z.

m3th0dman
fuente
3
Por supuesto, existe esa cosa maravillosa llamada inferencia de tipos, que le permite escribir algo como var addOne = (int x, long y, double z, String s) => { x + 1 }en un lenguaje de tipo estático no estúpido de su elección (ejemplos: C #, C ++, Scala). Incluso la inferencia de tipo local muy limitada utilizada por C # es completamente suficiente para esto. Entonces, esta respuesta es simplemente criticar una sintaxis específica que es dudosa en primer lugar, y que en realidad no se usa en ningún lugar (aunque la sintaxis de Haskell tiene un problema muy similar).
amon
44
@amon Su respuesta puede estar criticando la sintaxis, pero también señala que la sintaxis intencionada en la pregunta puede no ser "natural" para todos.
1
@amon La utilidad de la inferencia de tipos no es algo maravilloso para todos. Si lee el código más a menudo que escribe el código, entonces la inferencia de tipos es mala porque tiene que inferir en su cabeza el tipo al leer el código; y es mucho más rápido leer el tipo que pensar realmente sobre qué tipo se usa.
m3th0dman
1
La crítica me parece válida. Para Java, el OP parece pensar que [entrada, salida, nombre, entrada] es una función def más simple / clara que simplemente [salida, nombre, entrada]. Como dice @ m3th0dman, con firmas más largas, el enfoque 'más limpio' del OP se vuelve muy extenso.
Michael
0

Hay una razón muy simple para tener esa distinción en la mayoría de los idiomas: es necesario distinguir la evaluación y la declaración . Tu ejemplo es bueno: ¿por qué no te gustan las variables? Bueno, las expresiones de variables se evalúan de inmediato.

Haskell tiene un modelo especial donde no hay distinción entre evaluación y declaración, por lo que no hay necesidad de una palabra clave especial.

Florian Margaine
fuente
2
Pero alguna sintaxis para las funciones lambda también resuelve esto, entonces, ¿por qué no usar eso?
svick
0

Las funciones se declaran de manera diferente a los literales, objetos, etc. en la mayoría de los idiomas porque se usan de manera diferente, se depuran de manera diferente y plantean diferentes fuentes potenciales de error.

Si una referencia de objeto dinámico o un objeto mutable se pasa a una función, la función puede cambiar el valor del objeto mientras se ejecuta. Este tipo de efecto secundario puede dificultar el seguimiento de lo que hará una función si está anidada dentro de una expresión compleja, y este es un problema común en lenguajes como C ++ y Java.

Considere depurar algún tipo de módulo de kernel en Java, donde cada objeto tiene una operación toString (). Si bien puede esperarse que el método toString () restaure el objeto, es posible que deba desmontar y volver a ensamblar el objeto para traducir su valor a un objeto String. Si está tratando de depurar los métodos que toString () llamará (en un escenario de enlace y plantilla) para hacer su trabajo, y resalte accidentalmente el objeto en la ventana de variables de la mayoría de los IDE, puede bloquear el depurador. Esto se debe a que el IDE intentará toString () el objeto que llama al código que está en proceso de depuración. Ningún valor primitivo es tan malo porque el lenguaje, no el programador, define el significado semántico de los valores primitivos.

Trixie Wolf
fuente