Definir y llamar a una función
Una función en R es un valor, como un número o una cadena. Construyes una con la palabra clave function y la fijas a un nombre con <-, igual que guardarías cualquier otra cosa en una variable:
Las partes: function(x) declara un parámetro llamado x, las llaves contienen el cuerpo, y llamar a square(4) ejecuta el cuerpo con x valiendo 4. Para un cuerpo de una línea las llaves son opcionales - square <- function(x) x^2 es la misma función -, pero las llaves se leen mejor en cuanto el cuerpo crece.
Como una función no es más que un valor, todo lo que sabes sobre variables aplica: puedes reasignarla, pasarla a otra función o guardarla en una lista. Ese único hecho impulsa la mitad del R idiomático, incluida toda la familia apply.
Valores de retorno: gana la última expresión
Una función de R devuelve lo que produzca su última expresión evaluada. No hay ninguna sentencia return obligatoria:
return() sí existe, y funciona como esperarías - detiene la función de inmediato y devuelve su argumento. El R idiomático lo reserva para las salidas tempranas: abandonar al principio cuando una entrada hace que el resto del trabajo carezca de sentido. Combínalo con comprobaciones if-else:
Escribir return(a / b) en la última línea no estaría mal, solo sería ruido. Reserva return() para las salidas que ocurren pronto y deja que la última expresión hable por el camino normal.
Valores por defecto y argumentos con nombre
Un parámetro puede llevar un valor por defecto, declarado con = en la lista de parámetros. Quien llame y esté conforme con el valor por defecto simplemente omite el argumento:
La tercera llamada muestra la otra mitad de la historia: los argumentos con nombre. Cuando escribes name = "Ada" en el punto de llamada, la posición deja de importar - R empareja primero por nombre y luego rellena los parámetros restantes por posición. De aquí salen dos reglas prácticas:
- Pon primero los parámetros obligatorios y después los que tienen valor por defecto, para que las llamadas posicionales sigan siendo naturales.
- En el punto de llamada, nombra todo argumento que no sea obvio por su posición.
greet("Ada", punctuation = "?")es más claro que obligar a quien lee a contar comas.
Pasar argumentos con ...
El parámetro especial ... (que se pronuncia "dots", puntos) significa "cualquier número de argumentos extra". Una función que declara ... puede aceptar argumentos que nunca listó y reenviarlos a otra función:
A shout() no le importa cuántas palabras le pases - se las entrega todas a paste(). Fíjate en que punctuation viene después de los puntos: cualquier parámetro declarado después de ... solo se puede fijar por nombre, que es exactamente lo que quieres para las opciones. Este patrón de reenvío está por todas partes en R base - sapply(x, round, digits = 2) funciona porque sapply reenvía digits = 2 a round a través de su propio ....
El precio de los puntos es que las erratas se cuelan en silencio: escribe mal punctuation como punctation y simplemente se lo tragará ... en lugar de lanzar un error. Mantén pequeñas las funciones que usan puntos.
Funciones anónimas
Cuando una función solo se necesita una vez - típicamente como argumento de otra función - puedes saltarte el nombre por completo:
Ambas líneas hacen lo mismo. function(x) x^2 es la grafía clásica; \(x) x^2 es la forma abreviada añadida en R 4.1, donde \ sustituye a la palabra function. Son idénticas en todo salvo en las pulsaciones de teclado - la forma abreviada no es un tipo distinto de función.
Usa una función anónima cuando la operación sea de una línea y esté ligada a un solo punto de llamada. En cuanto pegues la misma lambda en dos sitios, o crezca más allá de una línea, dale un nombre - una función con nombre se puede probar y se documenta sola.
Ámbito: qué puede ver una función
R usa ámbito léxico: cuando una función necesita una variable que no encuentra entre sus propios parámetros y asignaciones locales, la busca en el entorno donde se definió la función - no donde se la llamó. En la práctica eso significa que una función puede leer variables del script que la rodea:
La otra cara: una asignación dentro de una función nunca se filtra hacia fuera. rate <- 0.5 dentro de change_inside crea una variable local nueva que muere cuando la función retorna; el rate exterior sigue imprimiendo 0.1. Esto es una característica - las funciones no pueden pisotear tu espacio de trabajo por accidente -, pero sorprende a quien empieza y espera que la asignación interior se quede. Si una función necesita entregar un resultado al mundo exterior, devuélvelo y asigna en el punto de llamada. (Existe un operador <<- que alcanza hacia fuera; trátalo como un olor a código hasta que lo necesites de verdad.)
Un ejemplo resuelto
Este es el patrón que da los frutos: te das cuenta de que estás repitiendo tres líneas de análisis, las envuelves en una función y la reutilizas. Digamos que no paras de resumir vectores de mediciones:
Todo lo de esta página está ahí dentro: un parámetro digits con valor por defecto, una llamada con nombre que lo sobrescribe y una última expresión (round(out, digits)) haciendo de retorno. La función se lee como una frase, funciona con cualquier vector numérico y vive en un solo sitio cuando decidas añadir una mediana.
Lo que te llevas
nombre <- function(args) { cuerpo }crea una función; la última expresión evaluada es su valor de retorno.return()es para las salidas tempranas, no para la última línea normal.- Los valores por defecto se declaran con
=en la lista de parámetros; los argumentos con nombre hacen que los puntos de llamada sean independientes del orden y legibles. ...acepta y reenvía cualquier argumento extra - potente, pero oculta las erratas.function(x)y\(x)son lo mismo; usa funciones anónimas para líneas sueltas de un solo uso.- Las funciones leen variables de donde fueron definidas; las asignaciones dentro de ellas se quedan dentro.
Lo siguiente: la familia apply - las funciones que toman tus funciones y las ejecutan sobre vectores y listas enteros.
Preguntas frecuentes
¿Cómo se crea una función en R?
Asigna un objeto function a un nombre: square <- function(x) { x^2 }. Los parámetros van entre paréntesis, el cuerpo entre llaves, y la llamas como square(4). La última expresión evaluada es lo que devuelve la función.
¿Hace falta return() en R?
No. Una función de R devuelve automáticamente el valor de la última expresión que evalúa. return() existe, y el R idiomático lo reserva para las salidas tempranas - abandonar al principio de una función cuando una entrada no es válida o se ha resuelto un caso límite.
¿Qué es una función anónima en R?
Una función que defines sin darle nombre, normalmente pasada directamente a otra función: sapply(x, function(v) v^2). Desde R 4.1 también existe la forma abreviada \(v) v^2, que significa exactamente lo mismo con menos pulsaciones.