Menu

Funzioni in R: definizione, argomenti e valori di ritorno

Come creare una funzione in R: la sintassi function(x) { }, i valori di ritorno, gli argomenti predefiniti e con nome, i ... (dots), le funzioni anonime e come funziona lo scope.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Definire e chiamare una funzione

In R una funzione è un valore, come un numero o una stringa. La costruisci con la parola chiave function e la leghi a un nome con <-, come faresti per salvare qualsiasi altra cosa in una variabile:

Le parti: function(x) dichiara un parametro chiamato x, le graffe contengono il corpo e la chiamata square(4) esegue il corpo con x impostato a 4. Per un corpo di una riga le graffe sono facoltative, square <- function(x) x^2 è la stessa funzione, ma le graffe si leggono meglio quando il corpo cresce.

Siccome una funzione è solo un valore, vale tutto ciò che sai sulle variabili: puoi riassegnarla, passarla a un'altra funzione o salvarla in una lista. Questo semplice fatto alimenta metà dell'R idiomatico, compresa l'intera famiglia apply.

Valori di ritorno: vince l'ultima espressione

Una funzione R restituisce ciò che produce la sua ultima espressione valutata. Non c'è un'istruzione return obbligatoria:

return() esiste e funziona come ti aspetteresti: ferma subito la funzione e restituisce il suo argomento. L'R idiomatico lo riserva alle uscite anticipate: abbandonare la funzione all'inizio quando un input rende inutile il resto del lavoro. Abbinalo ai controlli if-else:

Scrivere return(a / b) nell'ultima riga non sarebbe sbagliato, solo superfluo. Riserva return() alle uscite anticipate e lascia che sia l'ultima espressione a parlare per il percorso normale.

Valori predefiniti e argomenti con nome

Un parametro può avere un valore predefinito, dichiarato con = nell'elenco dei parametri. Chi chiama la funzione e va bene con il valore predefinito omette semplicemente l'argomento:

La terza chiamata mostra l'altra metà della storia: gli argomenti con nome. Quando scrivi name = "Ada" nella chiamata, la posizione smette di contare: R abbina prima per nome, poi riempie i parametri rimanenti per posizione. Ne derivano due regole pratiche:

  • Metti prima i parametri obbligatori e dopo quelli con un valore predefinito, così le chiamate per posizione restano naturali.
  • Nella chiamata, dai un nome a ogni argomento il cui significato non è ovvio dalla posizione. greet("Ada", punctuation = "?") è più chiaro che costringere chi legge a contare le virgole.

Passare argomenti con ...

Il parametro speciale ... (si legge "dots") significa "un numero qualsiasi di argomenti aggiuntivi". Una funzione che dichiara ... può accettare argomenti che non ha mai elencato e inoltrarli a un'altra funzione:

A shout() non importa quante parole passi: le consegna tutte a paste(). Nota che punctuation viene dopo i dots: qualsiasi parametro dichiarato dopo ... si può impostare solo per nome, ed è esattamente ciò che vuoi per le opzioni. Questo schema di inoltro è ovunque in R base: sapply(x, round, digits = 2) funziona perché sapply inoltra digits = 2 a round tramite i suoi ....

Il prezzo dei dots è che gli errori di battitura passano inosservati: scrivi punctation invece di punctuation e viene semplicemente inghiottito nei ... invece di sollevare un errore. Mantieni piccole le funzioni che usano i dots.

Funzioni anonime

Quando una funzione serve una volta sola, tipicamente come argomento di un'altra funzione, puoi fare a meno del nome:

Le due righe fanno la stessa cosa. function(x) x^2 è la forma classica; \(x) x^2 è l'abbreviazione introdotta in R 4.1, dove \ sta al posto della parola function. Sono identiche sotto ogni aspetto tranne i caratteri da scrivere: l'abbreviazione non è un tipo diverso di funzione.

Usa una funzione anonima quando l'operazione è una riga legata a un solo punto di chiamata. Appena incolli la stessa lambda in due punti, o supera una riga, dalle un nome: una funzione con nome si può testare e si documenta da sola.

Scope: cosa vede una funzione

R usa lo scope lessicale: quando una funzione ha bisogno di una variabile che non trova tra i propri parametri e assegnamenti locali, la cerca nell'ambiente in cui la funzione è stata definita, non in quello da cui è stata chiamata. In pratica significa che una funzione può leggere le variabili dello script che la circonda:

Il rovescio della medaglia: un assegnamento dentro una funzione non esce mai fuori. rate <- 0.5 dentro change_inside crea una nuova variabile locale che muore quando la funzione termina; il rate esterno stampa ancora 0.1. È una caratteristica voluta, perché le funzioni non possono calpestare per sbaglio il tuo workspace, ma sorprende chi inizia e si aspetta che l'assegnamento interno resti. Se una funzione deve consegnare un risultato all'esterno, restituiscilo e assegnalo nel punto di chiamata. (Esiste un operatore <<- che raggiunge l'esterno; consideralo un campanello d'allarme finché non ne hai davvero bisogno.)

Un esempio completo

Ecco lo schema che ripaga: ti accorgi di ripetere tre righe di analisi, le avvolgi in una funzione, la riusi. Supponi di riassumere spesso dei vettori di misure:

C'è dentro tutto ciò che hai visto in questa pagina: un parametro digits con valore predefinito, una chiamata con nome che lo sovrascrive e un'ultima espressione (round(out, digits)) che si occupa del ritorno. La funzione si legge come una frase, funziona su qualsiasi vettore numerico e sta in un unico posto quando deciderai di aggiungere la mediana.

Cosa ti porti a casa

  • name <- function(args) { body } crea una funzione; l'ultima espressione valutata è il suo valore di ritorno.
  • return() serve per le uscite anticipate, non per la normale ultima riga.
  • I valori predefiniti si dichiarano con = nell'elenco dei parametri; gli argomenti con nome rendono le chiamate leggibili e indipendenti dall'ordine.
  • ... accetta e inoltra qualsiasi argomento aggiuntivo: potente, ma nasconde gli errori di battitura.
  • function(x) e \(x) sono la stessa cosa; usa le funzioni anonime per righe singole usate una volta.
  • Le funzioni leggono le variabili dal punto in cui sono state definite; gli assegnamenti al loro interno restano all'interno.

Prossimo passo: la famiglia apply, le funzioni che prendono le tue funzioni e le eseguono su interi vettori e liste.

Domande frequenti

Come si crea una funzione in R?

Assegna un oggetto function a un nome: square <- function(x) { x^2 }. I parametri vanno tra le parentesi tonde, il corpo tra le graffe, e la chiami così: square(4). L'ultima espressione valutata è ciò che la funzione restituisce.

Serve return() in R?

No. Una funzione R restituisce automaticamente il valore dell'ultima espressione che valuta. return() esiste, e l'R idiomatico lo riserva alle uscite anticipate: abbandonare la funzione all'inizio quando un input non è valido o quando un caso limite è già stato gestito.

Cos'è una funzione anonima in R?

Una funzione che definisci senza darle un nome, di solito passata direttamente a un'altra funzione: sapply(x, function(v) v^2). Da R 4.1 esiste anche la forma abbreviata \(v) v^2, che significa esattamente la stessa cosa con meno caratteri da scrivere.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA