Menu

Funkcje w R: definicja, argumenty i wartości zwracane

Jak napisać funkcję w R: składnia function(x) { }, wartości zwracane, argumenty domyślne i nazwane, kropki ..., funkcje anonimowe i zasięg zmiennych.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Definiowanie i wywoływanie funkcji

Funkcja w R to wartość, tak jak liczba czy napis. Tworzysz ją słowem kluczowym function i przypinasz do nazwy przez <-, tak samo jak zapisujesz cokolwiek innego w zmiennej:

Części: function(x) deklaruje jeden parametr o nazwie x, klamry zawierają treść, a wywołanie square(4) wykonuje treść z x ustawionym na 4. Przy jednolinijkowej treści klamry są opcjonalne (square <- function(x) x^2 to ta sama funkcja), ale gdy treść rośnie, z klamrami czyta się lepiej.

Ponieważ funkcja to po prostu wartość, działa tu wszystko, co wiesz o zmiennych: możesz ją ponownie przypisać, przekazać do innej funkcji albo zapisać w liście. Ten jeden fakt napędza połowę idiomatycznego R, łącznie z całą rodziną apply.

Wartości zwracane: wygrywa ostatnie wyrażenie

Funkcja w R zwraca to, co daje jej ostatnie obliczone wyrażenie. Nie ma obowiązkowej instrukcji return:

return() istnieje i działa tak, jak się spodziewasz: natychmiast zatrzymuje funkcję i oddaje swój argument. Idiomatyczny R zostawia je dla wczesnych wyjść: przerwania na początku, gdy dane wejściowe sprawiają, że reszta pracy nie ma sensu. Łącz je ze sprawdzeniami if-else:

Napisanie return(a / b) w ostatniej linii nie byłoby błędem, tylko szumem. Zostaw return() dla wyjść, które następują wcześnie, a normalną ścieżkę niech wyraża ostatnie wyrażenie.

Wartości domyślne i argumenty nazwane

Parametr może mieć wartość domyślną zadeklarowaną przez = na liście parametrów. Wywołujący, którym wartość domyślna odpowiada, po prostu pomijają ten argument:

Trzecie wywołanie pokazuje drugą połowę historii: argumenty nazwane. Gdy w miejscu wywołania piszesz name = "Ada", pozycja przestaje mieć znaczenie: R najpierw dopasowuje po nazwie, a potem wypełnia pozostałe parametry po pozycji. Wynikają z tego dwie praktyczne zasady:

  • Umieszczaj wymagane parametry na początku, a te z wartościami domyślnymi po nich, żeby wywołania pozycyjne pozostały naturalne.
  • W miejscu wywołania nazywaj każdy argument, którego znaczenie nie wynika jasno z pozycji. greet("Ada", punctuation = "?") jest czytelniejsze niż zmuszanie czytelnika do liczenia przecinków.

Przekazywanie argumentów dalej przez ...

Specjalny parametr ... ("kropki") oznacza "dowolną liczbę dodatkowych argumentów". Funkcja, która deklaruje ..., może przyjąć argumenty, których nigdy nie wymieniła, i przekazać je do innej funkcji:

shout() nie wie i nie obchodzi jej, ile słów przekażesz: oddaje je wszystkie do paste(). Zwróć uwagę, że punctuation stoi po kropkach: każdy parametr zadeklarowany po ... można ustawić tylko po nazwie, a dokładnie tego chcesz dla opcji. Ten wzorzec przekazywania dalej jest wszędzie w bazowym R: sapply(x, round, digits = 2) działa, bo sapply przekazuje digits = 2 do round przez własne ....

Ceną kropek jest to, że literówki przechodzą po cichu: napisz punctuation jako punctation, a argument zostanie po prostu połknięty przez ... zamiast zgłosić błąd. Funkcje używające kropek utrzymuj małe.

Funkcje anonimowe

Gdy funkcja jest potrzebna tylko raz, zwykle jako argument innej funkcji, możesz całkiem pominąć nazwę:

Obie linie robią to samo. function(x) x^2 to klasyczny zapis; \(x) x^2 to skrót dodany w R 4.1, w którym \ zastępuje słowo function. Są identyczne pod każdym względem poza liczbą znaków: skrót nie jest innym rodzajem funkcji.

Używaj funkcji anonimowej, gdy operacja to jedna linijka związana z jednym miejscem wywołania. Gdy tylko wklejasz tę samą lambdę w dwa miejsca albo urasta ponad jedną linię, nadaj jej nazwę: funkcję nazwaną da się przetestować i sama się dokumentuje.

Zasięg: co widzi funkcja

R stosuje zasięg leksykalny (lexical scoping): gdy funkcja potrzebuje zmiennej, której nie znajduje wśród własnych parametrów i lokalnych przypisań, szuka jej w środowisku, w którym funkcja została zdefiniowana, a nie w tym, z którego ją wywołano. W praktyce oznacza to, że funkcja może czytać zmienne z otaczającego ją skryptu:

Druga strona medalu: przypisanie wewnątrz funkcji nigdy nie wycieka na zewnątrz. rate <- 0.5 wewnątrz change_inside tworzy nową zmienną lokalną, która znika, gdy funkcja się kończy; zewnętrzne rate wciąż wypisuje 0.1. To zaleta, bo funkcje nie mogą przypadkiem zadeptać przestrzeni roboczej, ale zaskakuje początkujących, którzy oczekują, że wewnętrzne przypisanie zostanie zachowane. Jeśli funkcja ma przekazać wynik na zewnątrz, zwróć go i przypisz w miejscu wywołania. (Istnieje operator <<-, który sięga na zewnątrz; traktuj go jako sygnał ostrzegawczy, dopóki naprawdę go nie potrzebujesz.)

Przykład w praktyce

Oto wzorzec, który się opłaca: zauważasz, że powtarzasz trzy linie analizy, owijasz je w funkcję i używasz jej ponownie. Powiedzmy, że ciągle podsumowujesz wektory pomiarów:

Jest tu wszystko z tej strony: parametr digits z wartością domyślną, nazwane wywołanie, które go nadpisuje, i ostatnie wyrażenie (round(out, digits)), które zwraca wynik. Funkcja czyta się jak zdanie, działa na dowolnym wektorze liczbowym i jest w jednym miejscu, gdy postanowisz dodać medianę.

Co warto zapamiętać

  • name <- function(args) { body } tworzy funkcję; ostatnie obliczone wyrażenie to jej wartość zwracana.
  • return() służy do wczesnych wyjść, nie do zwykłej ostatniej linii.
  • Wartości domyślne deklarujesz przez = na liście parametrów; argumenty nazwane uniezależniają wywołania od kolejności i czynią je czytelnymi.
  • ... przyjmuje i przekazuje dalej dowolne dodatkowe argumenty; to potężne, ale ukrywa literówki.
  • function(x) i \(x) to to samo; funkcji anonimowych używaj do jednorazowych jednolinijkowców.
  • Funkcje czytają zmienne z miejsca, w którym zostały zdefiniowane; przypisania wewnątrz nich zostają w środku.

Dalej: rodzina apply, czyli funkcje, które biorą twoje funkcje i uruchamiają je na całych wektorach i listach.

Najczęściej zadawane pytania

Jak utworzyć funkcję w R?

Przypisz obiekt function do nazwy: square <- function(x) { x^2 }. Parametry wpisujesz w nawiasach okrągłych, treść w klamrowych, a wywołujesz funkcję tak: square(4). Ostatnie obliczone wyrażenie jest wartością zwracaną przez funkcję.

Czy w R potrzebne jest return()?

Nie. Funkcja w R automatycznie zwraca wartość ostatniego obliczonego wyrażenia. return() istnieje, a idiomatyczny R rezerwuje je dla wczesnych wyjść: przerwania na początku funkcji, gdy dane wejściowe są nieprawidłowe albo obsłużony został przypadek brzegowy.

Czym jest funkcja anonimowa w R?

To funkcja zdefiniowana bez nadawania jej nazwy, zwykle przekazywana od razu do innej funkcji: sapply(x, function(v) v^2). Od R 4.1 istnieje też skrót \(v) v^2, który znaczy dokładnie to samo przy mniejszej liczbie znaków.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ