2.2 Funciones
“Everything that happens in R is the result of a function call.”
— John M. Chambers
Como es bien conocido, en R se pueden asignar los argumentos de una función por posición o por nombre (del correspondiente parámetro en la definición de la función, denominado argumento formal en R). En general, la recomendación es asignar los argumentos por nombre:
funcion(parametro1 = argumento1, parametro2 = argumento2, ...)
De esta forma no importa el orden de los parámetros y, por ejemplo, evitaremos problemas si en el futuro hay cambios en la definición de la función. Los parámetros pueden tener valores por defecto y solo sería necesario especificarlos para asignarles un valor distinto.
Podemos llamar a una función de un paquete sin necesidad de cargarlo (añadirlo a la ruta de búsqueda) empleando paquete::funcion
.
Esto es especialmente recomendable al desarrollar nuevas funciones (es un requisito para subir paquetes a CRAN), ya que de esta forma se evitan conflictos entre funciones con el mismo nombre en paquetes distintos.
Por ejemplo:
if (!requireNamespace("knitr")) stop("'knitr' package required")
::spin("01-Introduccion.R", knit = FALSE) knitr
Hay que tener en cuenta que R emplea Lazy evaluation, los argumentos no se evalúan hasta que se necesitan (lo cual puede producir mensajes de error inesperados, pero también permite añadir funcionalidades adicionales empleando la denominada evaluación no estándar o metaprogramación).
R es un lenguaje interpretado y podemos evaluar expresiones empleando código.
Por ejemplo, podemos reproducir el proceso de introducir un comando en la consola con las funciones eval()
y parse()
(aunque esta forma de proceder no es la más eficiente):
eval(parse(text = "1:10"))
## [1] 1 2 3 4 5 6 7 8 9 10
<- "norm" # "unif", "exp", "t"
distr <- eval(parse(text = paste0("d", distr)))
ddistr # str(ddistr)
# curve(ddistr(x, 0, 0.5), -3, 3)
Para llamar a una función especificando los parámetros de forma dinámica (empleando una lista) podemos emplear do.call()
.
Por ejemplo:
# Listar ficheros csv
<- dir(path = "datos", pattern = "*.csv", full.names = TRUE)
files.csv # Leer datos a una lista
# (suponemos variante local con ; para separar valores)
<- lapply(files.csv, read.csv2)
data.list # Combinar
<- do.call('rbind', data.list) datos
R dispone además de otras herramientas que permiten la programación dinámica.
Por ejemplo reformulate()
permite construir formulas para ajuste de modelos o análisis descriptivos.
Hay que tener en cuenta que las funciones tienen su propio entorno y su propia ruta de búsqueda, determinada por el entorno donde se crearon (el namespace en el caso de las funciones de un paquete). Esto es lo que se conoce como Lexical scoping.
<- 1
x <- function(y) {
addx + y
x
}addx(10)
## [1] 11
<- function() {
addx10 <- 10 # x <<- 10 # assign("x", 10, envir = .GlobalEnv)
x addx(x)
}addx10()
## [1] 11
x
## [1] 1