Определение и вызов функции
Функция в R — это значение, как число или строка. Вы строите её ключевым словом function и прикрепляете к имени через <-, точно так же, как сохранили бы что угодно другое в переменной:
Из чего состоит: function(x) объявляет один параметр с именем x, фигурные скобки содержат тело, а вызов square(4) выполняет тело с x, равным 4. Для однострочного тела фигурные скобки необязательны — square <- function(x) x^2 это та же функция, — но со скобками читается лучше, когда тело растёт.
Поскольку функция — просто значение, всё, что вы знаете о переменных, применимо и к ней: её можно переприсвоить, передать в другую функцию или сохранить в списке. Один этот факт питает половину идиоматичного R, включая всё семейство apply.
Возвращаемые значения: побеждает последнее выражение
Функция R возвращает то, что даёт её последнее вычисленное выражение. Обязательной инструкции return нет:
return() существует и работает так, как вы ожидаете: немедленно останавливает функцию и возвращает свой аргумент. Идиоматичный R приберегает его для досрочного выхода — прервать работу в начале, когда вход делает остальное бессмысленным. Сочетайте его с проверками if-else:
Написать return(a / b) на последней строке было бы не ошибкой, просто шумом. Приберегите return() для досрочных выходов, а нормальный путь пусть озвучивает последнее выражение.
Значения по умолчанию и именованные аргументы
Параметр может нести значение по умолчанию, объявленное через = в списке параметров. Вызывающие, которых устраивает умолчание, просто опускают аргумент:
Третий вызов показывает вторую половину истории — именованные аргументы. Когда вы пишете name = "Ada" в месте вызова, позиция перестаёт иметь значение: R сначала сопоставляет по имени, а затем заполняет оставшиеся параметры по позиции. Отсюда два практических правила:
- Ставьте обязательные параметры первыми, а параметры со значениями по умолчанию — после них, чтобы позиционные вызовы оставались естественными.
- В месте вызова именуйте любой аргумент, который не очевиден из позиции.
greet("Ada", punctuation = "?")понятнее, чем заставлять читателя считать запятые.
Проброс аргументов через ...
Специальный параметр ... (произносится «многоточие») означает «любое число дополнительных аргументов». Функция, объявившая ..., может принимать аргументы, которые она никогда не перечисляла, и пробрасывать их в другую функцию:
shout() не знает и не интересуется, сколько слов вы передаёте, — она отдаёт их все в paste(). Обратите внимание, что punctuation идёт после многоточия: любой параметр, объявленный после ..., можно задать только по имени, а это ровно то, что нужно для опций. Такой шаблон проброса встречается в базовом R повсюду — sapply(x, round, digits = 2) работает потому, что sapply пробрасывает digits = 2 в round через собственное ....
Цена многоточия в том, что опечатки проскакивают молча: напишите punctation вместо punctuation — и это просто проглотится в ... вместо ошибки. Держите функции с многоточием небольшими.
Анонимные функции
Когда функция нужна лишь однажды — обычно как аргумент другой функции, — имя можно вообще пропустить:
Обе строки делают одно и то же. function(x) x^2 — классическое написание; \(x) x^2 — сокращение, добавленное в R 4.1, где \ заменяет слово function. Они идентичны во всём, кроме числа нажатий клавиш, — сокращение не является другим видом функции.
Используйте анонимную функцию, когда операция — однострочник, привязанный к одному месту вызова. В момент, когда вы вставили ту же лямбду в двух местах или она выросла больше строки, дайте ей имя: именованная функция тестируема и самодокументируема.
Области видимости: что видит функция
R использует лексическую область видимости: когда функции нужна переменная, которую она не находит среди своих параметров и локальных присваиваний, она смотрит в окружение, где функция была определена, а не где она была вызвана. На практике это означает, что функция может читать переменные из окружающего скрипта:
Обратная сторона: присваивание внутри функции никогда не просачивается наружу. rate <- 0.5 внутри change_inside создаёт свежую локальную переменную, которая умирает при возврате из функции; внешняя rate по-прежнему печатает 0.1. Это преимущество — функции не могут случайно затоптать ваше рабочее пространство, — но оно удивляет новичков, ожидающих, что внутреннее присваивание сохранится. Если функции нужно передать результат наружу, верните его и присвойте в месте вызова. (Существует оператор <<-, дотягивающийся наружу; считайте его признаком плохого кода, пока он вам действительно не понадобится.)
Разобранный пример
Вот шаблон, ради которого всё затевалось: заметив, что вы повторяете три строки анализа, оберните их в функцию и переиспользуйте. Допустим, вы постоянно сводите векторы измерений:
Здесь есть всё с этой страницы: параметр digits со значением по умолчанию, именованный вызов, который его переопределяет, и последнее выражение (round(out, digits)), выполняющее возврат. Функция читается как предложение, работает на любом числовом векторе и живёт в одном месте, когда вы решите добавить медиану.
Что вы уносите с собой
name <- function(args) { body }создаёт функцию; её возвращаемое значение — последнее вычисленное выражение.return()— для досрочных выходов, а не для обычной последней строки.- Значения по умолчанию объявляются через
=в списке параметров; именованные аргументы делают вызовы независимыми от порядка и читаемыми. ...принимает и пробрасывает любые дополнительные аргументы — мощно, но скрывает опечатки.function(x)и\(x)— одно и то же; используйте анонимные функции для разовых однострочников.- Функции читают переменные оттуда, где были определены; присваивания внутри них остаются внутри.
Дальше: семейство apply — функции, которые берут ваши функции и запускают их по целым векторам и спискам.
Часто задаваемые вопросы
Как создать функцию в R?
Присвойте объект function имени: square <- function(x) { x^2 }. Параметры идут в круглых скобках, тело — в фигурных, а вызываете вы её как square(4). Функция возвращает последнее вычисленное выражение.
Нужен ли return() в R?
Нет. Функция R автоматически возвращает значение последнего вычисленного выражения. return() существует, и идиоматичный R приберегает его для досрочного выхода — когда нужно прервать работу в начале функции, если вход некорректен или обработан краевой случай.
Что такое анонимная функция в R?
Функция, которую вы определяете, не давая ей имени, обычно передавая прямо в другую функцию: sapply(x, function(v) v^2). Начиная с R 4.1 есть также сокращение \(v) v^2, означающее ровно то же самое при меньшем числе нажатий клавиш.