.. raw:: html
5. Función
==========
Una **función** es una “subrutina” que puede ser llamada por un código
externo. Como parte del programa, la función en sí también es una pieza
de código. Una función puede tener 0 o más parámetros y devolverá un
resultado, que se denomina **valor de retorno** de la función.
En Berry, la función es un **valor de primera clase**. Por lo tanto,
además de llamar a funciones, también puede pasar funciones como
valores, por ejemplo, vincular funciones a variables, usar funciones
como valores devueltos, etc.
5.1 Información básica
----------------------
El uso de funciones incluye dos partes: definición de función y llamada.
La declaración de definición de función usa la palabra clave ``def``
como el comienzo. La definición de la función es el proceso de
empaquetar y nombrar el código del cuerpo de la función. Este proceso
solo genera la estructura de la función y no ejecuta la función. La
función de ejecución debe usar un **operador de llamada**, que es un par
de paréntesis. El operador de llamada actúa sobre una expresión cuyo
resultado es un tipo de función. Los parámetros que se pasan a la
función se escriben entre paréntesis y los parámetros múltiples se
separan con comas. El resultado de la expresión de llamada es el valor
de retorno de la función.
5.1.1 Definición de funciones
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Función con nombre
^^^^^^^^^^^^^^^^^^
Una **función con nombre** es una función a la que se le da un nombre
cuando se define. Su declaración de definición consta de las siguientes
partes: palabra clave ``def``, nombre de funcion, lista que constan de 0
a múltiples parámetros y cuerpo de función, múltiples parámetros en la
lista de parámetros están separados por comas, y todos los parámetros
están escritos en un par de paréntesis. Llamamos al parámetro cuando la
función se define como **Parámetros formales**, y al parámetro cuando
llamamos a la función como **Argumentos**. La forma general de la
definición de la función es:
.. code::
’def’ name ´(´ argumentos ´)´
bloque
´end’
El nombre de función **nombre** es un identificador; **argumentos** es
la lista de parámetros formales; **bloque** es el cuerpo de la función.
Si el cuerpo de la función es una declaración vacía, la función se
denomina “función vacía”. La declaración del valor de retorno de la
función está contenida en el cuerpo de la función. Si no hay declaración
de devolución en **bloque**, la función devolverá ``nil`` por defecto.
El nombre de la función es en realidad el nombre de la variable del
objeto de la función vinculada. Si el nombre ya existe en el ámbito
actual, definir la función equivale a vincular el objeto de función a
esta variable.
El siguiente ejemplo define una función llamada ``add``. La función de
este ejemplo es sumar dos números y devolver el resultado.
.. code:: berry
def add(a, b)
return a + b
end
La función ``add`` tiene dos parámetros ``a`` y ``b``, y los dos
sumandos se pasan a la función a través de estos parámetros para el
cálculo. La instrucción ``return`` devuelve el resultado del cálculo.
Una función como atributo de clase se llama método. Esta parte del
contenido se explicará en el capítulo orientado a objetos.
Función anónima
^^^^^^^^^^^^^^^
A diferencia de las funciones con nombre, la **función anónima** no
tiene nombre y su expresión de definición tiene la forma:
.. code::
´def’ ´(´ argumentos ´)´
bloque
´end’
Se puede ver que, en comparación con las funciones con nombre, no hay un
**nombre** de función en su definición.. La definición de una función
anónima es esencialmente una expresión, que se denomina **Función
literal**. Para usar funciones anónimas podemos vincular el valor
literal de la función a una variable:
.. code:: berry
add = def (a, b)
return a + b
end
La función de este código es exactamente la misma que la función ``add``
en la sección anterior. Se puede usar una función anónima para pasar
convenientemente el valor de la función como un valor literal. Al igual
que otros tipos de literales, los literales de función también son la
unidad de expresión más pequeña. Por lo tanto, lo que hay entre las
palabras clave ``def`` y ``end`` es un todo indivisible.
Función de llamada
~~~~~~~~~~~~~~~~~~
Tome la función ``add`` como ejemplo. Para llamar a esta función, debe
proporcionar dos valores y puede obtener la suma de los dos números
llamando a la función:
.. code:: berry
res = add(5, 3)
print(res) # 8
Llamamos a la función llamada (la función ``add`` en el ejemplo) como
**Función llamada**, y la función que llama a la función llamada (la
función ``principal`` en el ejemplo) como **Función clave**. El proceso
de llamada de función es el siguiente: Primero, el intérprete
(implícitamente) inicializará la lista de parámetros formales de la
función llamada con la lista de argumentos y, al mismo tiempo,
suspenderá la función de llamada y guardará su estado, luego creará un
entorno para la función llamada y ejecutará la función llamada.
La función finalizará su ejecución cuando encuentre la instrucción
``return`` y pase el valor de retorno a la función que llama. El
intérprete destruirá el entorno de la función llamada después de que
regrese la función llamada, luego restaurará el entorno de la función
que llama y continuará ejecutando la función que llama. El valor de
retorno de la función también es el resultado de la expresión de la
llamada a la función. El siguiente ejemplo define una función
``cuadrado`` y vincula esta función a una variable ``f``, y luego llama
a la función ``cuadrado`` a través de la variable ``f``. Este uso es
similar a los punteros de función en lenguaje C.
.. code:: berry
def cuadrado(n)
return n * n
end
f = cuadrado
print(f(5)) # 25
Cabe señalar que el objeto de la función solo está vinculado a estas
variables (consulte la sección Capitulo-3: Operador de asignación
.. code:: berry
f = cuadrado
cuadrado = nil
print(f(5)) # 25
Se puede ver que la función todavía se puede llamar normalmente después
de reasignar ``cuadrado``. Solo después de que el objeto de función ya
no esté vinculado a ninguna variable, se perderá y el sistema reciclará
los recursos ocupados por este tipo de objeto de función.
Desviar la llamada
^^^^^^^^^^^^^^^^^^
La llamada de la función debe estar en el ámbito de la variable de
función, por lo que normalmente no se puede llamar antes de que se
defina la función. Para resolver este problema, puede utilizar este
método para comprometer:
.. code:: berry
var func1
def func2(x)
return func1(x)
end
def func1(x)
return x * x
end
print(func2(4)) # 16
En este ejemplo, ``func2`` llama a ``func1``, pero la función ``func1``
se define después de ``func2``. Después de ejecutar este código, el
programa generará el resultado correcto ``16``. Esta rutina utiliza el
mecanismo de que no se llamará a la función cuando se defina. Defina la
variable ``func1`` antes de definir ``func2`` para asegurarse de que el
símbolo ``func1`` no se encontrará durante la compilación. Luego
definimos la función ``func1`` después de ``func2`` para que la función
se use para sobrescribir el valor de la variable ``func1``. Cuando se
llama a la función ``func2`` en la última línea ``print(func2(4))``, la
variable ``func1`` ya es la función que necesitamos, por lo que se
mostrará el resultado correcto.
Llamada recursiva
^^^^^^^^^^^^^^^^^
Con **función recursiva** se refiere a funciones que se llaman a sí
mismas directa o indirectamente. La recursividad se refiere a una
estrategia que divide el problema en subproblemas similares y luego los
resuelve. Tomando el factorial como ejemplo, la definición recursiva de
factorial es 0! = 1, *n*! = *n* ⋅ (*n*\ −1)!. Entonces podemos escribir
la función recursiva para calcular el factorial según la definición:
.. code:: berry
def fact(n)
if n == 0
return 1
end
return n * fact(n-1)
end
Tome el factorial de 5 como ejemplo, el proceso de calcular manualmente
el factorial de 5 es: ¡5! = 5 × 4 × 3 × 2 × 1 = 120. El resultado de
llamar a la función ``fact`` también es 120:
.. code:: berry
print(fact(5)) # 120
Para garantizar que la profundidad de la llamada recursiva sea limitada
(un nivel de recursividad demasiado profundo agotará el espacio de la
pila), la función recursiva debe tener una condición de finalización. En
``fact`` la declaración ``if`` en la segunda línea de la definición de
la función se usa para detectar la condición final, y el proceso
recursivo finaliza cuando ``n`` se calcula como ``0``. La fórmula
factorial anterior no se aplica a parámetros no enteros. Ejecutar una
expresión como ``fact(5.1)`` provocará un error de desbordamiento de
pila debido a la imposibilidad de finalizar la recursividad.
Existe otra situación, la ``Recurrencia indirecta``, es decir, la
función no es llamada por sí misma sino por otra función (directa o
indirectamente) llamada por ella. La recursividad indirecta generalmente
requiere el uso de técnicas de llamada de función hacia adelante. Tome
las funciones ``es_impar`` y ``es_par`` para calcular números pares e
impares como ejemplos:
.. code:: berry
var es_impar
def es_par(n)
if n == 0
return true
end
return es_impar(n-1)
end
def es_impar(n)
if n == 0
return false
end
return es_par(n-1)
end
Estas dos funciones se llaman entre sí. Para garantizar que este nombre
esté en el alcance cuando se llama a la función ``es_impar`` en la línea
6, la variable ``es_impar`` se define en la línea 1.
Llamada de función anónima
^^^^^^^^^^^^^^^^^^^^^^^^^^
Si una función anónima solo se llamará una vez, la forma más fácil es
llamarla cuando esté definida, por ejemplo:
.. code:: berry
res = def (a, b) return a + b end (1, 2) # 3
En esta rutina, usamos la expresión de llamada directamente después del
literal de función para llamar a la función. Este uso es muy adecuado
para funciones que solo se llamarán en un lugar.
También puede vincular una función anónima a una variable y llamarla:
.. code:: berry
add = def (a, b) return a + b end
res = add(1, 2) # 3
Este uso es similar a la llamada de una función con nombre,
esencialmente llamando a la variable vinculada al valor de la función.
Cabe señalar que es más difícil realizar llamadas recursivas a funciones
anónimas, a menos que utilice técnicas de llamada de reenvío.
Parámetros formales y reales
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
La función utiliza parámetros reales para inicializar los parámetros
formales cuando se llama. En circunstancias normales, el parámetro real
y el parámetro de forma son iguales y las posiciones se corresponden
entre sí, pero Berry también permite que el parámetro real sea diferente
del parámetro formal: si el parámetro real es mayor que el parámetro
formal, el parámetro real adicional al parámetro será descartado. De
otra forma los parámetros formales restantes se inicializarán a ``nil``.
El proceso de paso de parámetros es similar a la operación de
asignación. Para los tipos ``nil``, ``boolean`` y numéricos, el paso de
parámetros es por valor, mientras que otros tipos son por referencia.
Para el tipo de referencia de paso de escritura, como una instancia,
modificarlos en la función llamada también modificará el objeto en la
función de llamada. El siguiente ejemplo demuestra esta función:
.. code:: berry
var l = [], i = 0
def func(a, b)
a.push(1)
b ='cadena'
end
func(l, i)
print(l, i) # [1] 0
Se puede ver que el valor de la variable ``l`` ha cambiado después de
llamar a la función ``func``, pero el valor de la variable ``i`` no ha
cambiado.
Función con número variable de argumentos (vararg)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Puede definir una función para tomar cualquier número arbitrario de
argumentos e iterarlos. Por ejemplo, ``print()`` toma cualquier cantidad
de argumentos e imprime cada uno de ellos separados por espacios. Debe
definir el último argumento como una captura de todos los argumentos
usando ``*`` antes de su nombre.
Todos los argumentos que siguen a los argumentos formales se agrupan en
tiempo de ejecución en una instancia de ``list``. Si no se capturan
argumentos, la lista está vacía.
Ejemplo:
.. code:: berry
def f(a, b, *c) return size(c) end
f(1,2) # devuelve 0, c is []
f(1,2,3) # devuelve 1, c is [3]
f(1,2,3,4) # devuelve 2, c is [3,4]
Llamar a una función con un número dinámico de argumentos
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
La sintaxis de Berry solo permite llamar con un número fijo de
argumentos. Utilice la función ``call(f, [args])`` para pasar cualquier
número de argumentos arbitrario.
Puede agregar estáticamente cualquier número de argumentos a ``call()``.
Si el último argumento es una ``lista``, se expande automáticamente a
argumentos discretos.
Ejemplo:
.. code:: berry
def f(a,b) return nil end
call(f,1) # llama a f(1)
call(f,1,2) # llama a f(1,2)
call(f,1,2,3) # llama a f(1,2,3), el último argumento es ignorado por f
call(f,1,[2,3]) # llama a f(1,2,3), el último argumento es ignorado por f
call(f,[1,2]) # llama a f(1,2)
call(f,[]) # llama a f()
Puede combinar ``call`` y vararg. Por ejemplo, creemos una función que
actúe como ``print()`` pero convierta todos los argumentos a mayúsculas.
Ejemplo completo:
.. code:: berry
def print_upper(*a) # toma un número arbitrario de argumentos, args es una lista
import string
for i:0..size(a)-1
if type(a[i]) == 'string'
a[i] = string.toupper(a[i])
end
end
call(print, a) # llama a print con todos los argumentos
end
print_upper("a",1,"Foo","Bar") # imprime: A 1 FOO BAR
Funciones y variables locales
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
El cuerpo de la función en sí es un ámbito, por lo que las variables
definidas en la función son todas variables locales. A diferencia de los
bloques directamente anidados, cada vez que se llama a una función, se
asigna espacio para las variables locales. El espacio para las variables
locales se asigna en la pila y la información de asignación se determina
en el momento de la compilación, por lo que este proceso es muy rápido.
Cuando se anidan varios niveles de alcance en una función, el intérprete
asigna espacio de pila para la cadena de anidamiento de alcance con la
mayoría de las variables locales, en lugar del número total de variables
locales en la función.
Declaración ``return``
~~~~~~~~~~~~~~~~~~~~~~
La declaración ``return`` se utiliza para devolver el resultado de una
función, es decir, el valor de retorno de la función. Todas las
funciones en Berry tienen un valor de retorno, pero no puede usar
ninguna declaración ``return`` en el cuerpo de la función. En este
momento, el intérprete generará una declaración ``return``
predeterminada para garantizar que la función regrese ``return``. Hay
dos formas de escribir oraciones:
.. container:: algorithm
::
´return’
´return’ expresión
La primera forma de escribir es escribir solo la palabra clave
``return`` y no la expresión que se devolverá. En este caso, se devuelve
el valor ``nil`` predeterminado. La segunda forma de escribir es seguir
la expresión **expresión** después de la palabra clave ``return``, y el
valor de la expresión se usará como valor de retorno de la función.
Cuando el programa ejecuta la declaración ``return``, la función que se
está ejecutando actualmente finalizará la ejecución y volverá al código
que llamó a la función para continuar ejecutándose.
Cuando se usa una palabra clave separada ``return`` como declaración de
retorno de una función, es fácil causar ambigüedad. En ese caso se
recomienda agregar un punto y coma después de ``return`` para evitar
errores:
.. code:: berry
def func()
return;
x = 1
end
En este ejemplo, la declaración ``x = 1`` después de la declaración
``return`` no se ejecutará, por lo que es redundante. Si se evita este
tipo de código redundante, la instrucción ``return`` suele ir seguida de
palabras clave como ``end``, ``else`` o ``elif``. En este caso, incluso
si se usa una declaración ``return`` por separado, no hay necesidad de
preocuparse por la ambigüedad.
Cierre (closure)
----------------
Conceptos básicos
~~~~~~~~~~~~~~~~~
Como se mencionó anteriormente, las funciones son el primer tipo de
valor en Berry. Puede definir funciones en cualquier lugar y también
puede pasar funciones como parámetros o devolver valores. Cuando se
define otra función en una función, la función anidada puede acceder a
las variables locales de cualquier función externa. Llamamos a las
“variables locales de la función externa” utilizadas en la función la
función como **Variables libres**. Las variables libres generalizadas
también incluyen variables globales, pero no existe tal regla en Berry.
El **Cierre** es una técnica que vincula funciones a **entornos**. El
entorno es un mapeo que asocia cada variable libre de una función con un
valor. En términos de implementación, los cierres asocian el prototipo
de función con sus propias variables. Los prototipos de funciones se
generan en tiempo de compilación y el entorno es un concepto de tiempo
de ejecución, por lo que los cierres también se generan dinámicamente en
tiempo de ejecución. Cada cierre vincula el prototipo de función al
entorno cuando se genera, como se ve en el siguiente ejemplo:
.. code:: berry
def func(i) # La función externa
def foo() # La función interna (closure)
print(i)
end
foo()
end
La función interna ``foo`` es un cierre y tiene una variable libre
``i``, que es un parámetro de la función externa ``func``. Cuando se
genera el cierre ``foo``, su prototipo de función se vincula al entorno
que contiene la variable libre ``i``. Cuando la variable ``foo`` sale
del alcance, el cierre se destruirá. Por lo general, la función interna
será el valor de retorno de la función externa, por ejemplo:
.. code:: berry
def func(i) # La función externa
return def () # Devuelve un cierre (función anónima)
print(i)
i = i + 1
end
end
El cierre devuelto aquí es una función anónima. Cuando la función
externa devuelve el cierre, las variables locales de la función externa
se destruirán y el cierre no podrá acceder directamente a las variables
en la función externa original. El sistema copiará el valor de la
variable libre al entorno cuando se destruya la variable libre. El ciclo
de vida de estas variables libres es el mismo que el del cierre, y solo
el cierre puede acceder a ellas. La función o el cierre devuelto no se
ejecutará automáticamente, por lo que debemos llamar al cierre devuelto
por la función ``func``:
.. code:: berry
f = func(0)
f()
Este código generará ``0``. Si continuamos llamando al cierre ``f``,
obtendremos la salida ``1``, ``2``, ``3``\ … Esto puede no entenderse
bien: la variable [2.198 ] se destruye después de que la función
``func`` regresa , y como la variable libre del cierre ``f``, ``i`` se
almacenará en el entorno de cierre, por lo que cada vez que se llame a
``f``, el valor de ``i`` se sumará a 1 (definición de la función
``func`` línea 4).
Uso de cierres
^^^^^^^^^^^^^^
Los cierres tienen muchos usos. Aquí hay algunos usos comunes:
Evaluación perezosa
'''''''''''''''''''
El cierre no hace nada hasta que se llama.
Función de comunicación privada
'''''''''''''''''''''''''''''''
Puede permitir que algunos cierres compartan variables libres, que solo
son visibles para estos cierres, y se comuniquen entre funciones
cambiando los valores de estas variables libres. Esto puede evitar el
uso de variables externas.
Generar múltiples funciones
'''''''''''''''''''''''''''
A veces es posible que necesitemos usar múltiples funciones, estas
funciones pueden tener solo diferentes valores de algunas variables.
Podemos implementar una función y luego usar estas diferentes variables
como parámetros de función. Una mejor manera es devolver el cierre a
través de una función de fábrica y usar estas variables posiblemente
diferentes como variables libres del cierre, de modo que no siempre
tenga que escribir esos parámetros al llamar a la función, y cualquier
número de funciones similares puede ser generado.
Simular miembros privados
'''''''''''''''''''''''''
Algunos lenguajes admiten el uso de miembros privados en objetos, pero
la clase de Berry no lo admite. Podemos usar las variables libres de los
cierres para simular miembros privados. Este uso no es la intención
original de diseñar cierres, pero hoy en día, este “mal uso” de los
cierres es muy común.
Resultado de caché
''''''''''''''''''
Si hay una función que requiere mucho tiempo para ejecutarse, llevará
mucho tiempo llamarla cada vez. Podemos almacenar en caché el resultado
de esta función, buscarlo en el caché antes de llamar a la función y
devolver el valor almacenado en caché si lo encuentra; de lo contrario,
se llama a la función y se actualiza el valor almacenado en caché.
Podemos usar los cierres para guardar el valor almacenado en caché para
que no quede expuesto al alcance externo, y el resultado almacenado en
caché se conservará (hasta que se destruya el cierre).
Vinculación de variables libres
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Si varios cierres vinculan la misma variable libre, todos los cierres
siempre compartirán esta variable libre. Por ejemplo:
.. code:: berry
def func(i) # La función externa
return [# Devuelve la lista de cierre
def () # El cierre #1
print("cierre 1 log:", i)
i = i + 1
end,
def () # El cierre #2
print("cierre 2 log:", i)
i = i + 1
end
]
end
La función ``func``, en este ejemplo, devuelve dos cierres a través de
una lista, y estos dos cierres comparten la variable libres ``i``. Si
llamamos a estos cierres:
.. code:: berry
f = func(0)
f[0]() # cierre 1 log: 0
f[1]() # cierre 2 log: 1
Como puede ver, actualizamos la variable libre ``i`` cuando llamamos al
cierre ``f[0]``, y este cambio afectó el resultado de llamar al cierre
``f[1]``. Esto se debe a que si varios cierres utilizan una variable
libre, solo hay una copia de la variable libre y todos los cierres
tienen una referencia a la entidad de variable libre. Por lo tanto,
cualquier modificación a la variable libre es visible para todos los
cierres que usan dicha variable.
De manera similar, antes de que se destruyan las variables locales de la
función externa, modificar el valor de la variable libre también
afectará el cierre:
.. code:: berry
def func()
i = 0
def foo()
print(i)
end
i = 1
return foo
end
En este ejemplo cambiamos el valor de la variable ``i`` (que es la
variable libre del cierre ``foo``) de ``0`` a ``1`` antes de que regrese
la función externa ``func``, luego llamamos al cierre, y después el
valor de la variable libre ``i`` cuando el paquete ``foo`` también es
``1``:
.. code:: berry
func()() # 1
Crear cierre en bucle
~~~~~~~~~~~~~~~~~~~~~
Al construir un cierre en el cuerpo del ciclo, es posible que no desee
que las variables libres del cierre cambien con las variables del ciclo.
Primero veamos un ejemplo de cómo crear un cierre en un bucle ``while``:
.. code:: berry
def func()
l = [] i = 0
while i <= 2
l.push(def () print(i) end)
i = i + 1
end
return l
end
En este ejemplo, construimos un cierre en un ciclo y colocamos este
cierre en una ``lista``. Obviamente, cuando finalice el ciclo, el valor
de la variable ``i`` será ``3``, y todos los cierres de la lista ``l``
también son referencias usando esta variable. Si ejecutamos el cierre
devuelto por ``func`` obtendremos el mismo resultado:
.. code:: berry
res = func()
res[0]() # 3
res[1]() # 3
res[2]() # 3
Si queremos que cada cierre se refiera a diferentes variables libres,
podemos definir otra capa de funciones y luego vincular las variables
del ciclo actual con los parámetros de la función:
.. code:: berry
def func()
l = [] i = 0
while i <= 2
l.push(def (n)
return def () print(n) end
end (i))
i = i + 1
end
return l
end
Para ayudar a entender este código aparentemente incomprensible, nos
enfocaremos en el código de las líneas 4 a 6:
.. code:: berry
def (n)
return def ()
print(n)
end
end (i)
Aquí realmente se define una función anónima y se llama inmediatamente.
La función de esta función anónima temporal es vincular el valor de la
variable de bucle ``i`` a su parámetro ``n``, y la variable ``n``
también es lo que necesitamos para cerrar las variables libres del
paquete, de modo que las las variables vinculadas al cierre construido
durante cada ciclo son diferentes. Ahora obtendremos la salida deseada:
.. code:: berry
res = func()
res[0]() # 0
res[1]() # 1
res[2]() # 2
Hay algunas formas de resolver el problema de las variables de bucle
como variables libres. Una forma un poco más simple es definir una
variable temporal en el cuerpo del bucle:
.. code:: berry
def func()
l = [] i = 0
while i <= 2
temp = i
l.push(def () print(temp) end)
i = i + 1
end
return l
end
Aquí ``temp`` es una variable temporal. El alcance de esta variable está
en el cuerpo del ciclo, por lo que se redefinirá cada vez que se realice
un ciclo. También podemos usar la instrucción ``for`` para resolver el
problema:
.. code:: berry
def func()
l = []
for i: 0 .. 2
l.push(def () print(i) end)
end
return l
end
Esta puede ser la forma más sencilla de\ ``for``. La variable de
iteración de la instrucción se creará en cada ciclo. El principio es
similar al método anterior.
Expresión lambda
----------------
La **Expresión lambda** es una función anónima especial. La expresión
lambda se compone de una lista de parámetros y un cuerpo de función,
pero la forma es diferente de la función general:
.. code::
´/´ args ´->´ expr ´end’
**args** es la lista de parámetros, la cantidad de parámetros puede ser
cero o más, y los parámetros múltiples están separados por comas o
espacios (no se pueden mezclar al mismo tiempo); **expr** es la
expresión de retorno, la expresión lambda devolverá el valor de la
expresión. Las expresiones lambda son adecuadas para implementar
funciones muy simples. Por ejemplo, la expresión lambda para juzgar el
tamaño de dos números es:
.. code:: berry
/ a b -> a < b
Esto es más fácil que escribir una función con la misma funcionalidad.
En algunos algoritmos generales de clasificación, este tipo de función
de comparación de tamaño puede necesitar un uso extensivo. El uso de
expresiones lambda puede simplificar el código y mejorar la legibilidad.
Al igual que las funciones generales, las expresiones lambda pueden
formar cierres. Las expresiones lambda se llaman de la misma manera que
las funciones ordinarias. Si usa el método de llamada inmediata similar
a las funciones anónimas:
.. code:: berry
lambda = / a b -> a < b
result = lambda(1, 2) # llamada normal
result = (/ a b -> a < b)(1, 2) # llamada directa
Dado que el operador de llamada de función tiene una prioridad más alta,
se debe agregar un par de paréntesis a la expresión lambda cuando se
realiza una llamada directa, para que se llame como un todo.