«Метафункция» в R для создания функций с оцененным/явным параметром? (не знаю, как точно это сформулировать)

Я хочу создать функцию, которая возвращает другую функцию с параметром из первой, например.

foo1 <- function(y) function(x) x+y

(Обновлено: изначально я написал foo1 <- function(y) function(x+y), изменил это. Также см. ответ @Konrad Rudolph о том, почему это плохое определение.)

но! Я хотел бы увидеть, какое значение параметра «y» было выбрано. Вышеупомянутое печатает как

foo1(1.2)
#> function(x) x + y
#> <environment: 0x000001dd24275a90>

Теперь я мог бы добиться этого через

foo2 <- function(y){
    eval(parse(text = sprintf("function(x) x + %s", y)))
}

Затем печать «foo2» показывает, какое значение параметра «y» использовалось при его создании.

foo2(1.2)
#> function(x) x + 1.2
#> <environment: 0x000001dd242604a0>

Однако я подозреваю, что есть более элегантное решение.

Я думал что-то вроде

foo3 <- function(y){
   eval(substitute(function(x) x+dummy, env = list(dummy=y)))
}

могло бы сработать, но нет. Это будет напечатано

foo3(1.2)
#> function(x) x+dummy
#> <environment: 0x000001dd23e137d0>

Есть ли у кого-нибудь более элегантное решение, чем мой «foo2»?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Прежде всего, помните, что ваша исходная функция не работает (помимо синтаксической ошибки):

foo1 <- function(y) function(x) x+y

a <- 10
myfoo <- foo1(a)

a <- 20
myfoo(1)
# [1] 21

Вероятно, вы хотели, чтобы последний вызов возвращал 11, а не 21.

Чтобы это исправить, нам нужно принудительно выполнить нетерпеливую оценку y — иначе она будет лениво оцениваться при использовании, а не раньше:

foo1 <- function (y) {
    force(y)
    function (x) x + y
}

Далее, чтобы ответить на ваш актуальный вопрос: ваш foo3 почти работает! R просто обманывает вас, потому что он хранит «исходный код» функции в атрибуте (srcref) функции. И при отображении определения функции через print он печатает это srcref (если доступно) вместо фактического тела. Мы можем удалить атрибут, чтобы исправить это:

foo <- function (y) {
    fun <- eval(substitute(function(x) x + dummy, env = list(dummy = y)))
    attr(fun, 'srcref') <- NULL
    fun
}
foo(1.2)
# x + 1.2
# <environment: 0x108952138>

(Обратите внимание, что нам не нужно явно принудительно вычислять y в этом определении foo(), поскольку передача его в list() (а затем в substitute()) все равно приведет к его вычислению.)

Это решение прекрасно работает! Хотя мне придется использовать 'attr(fun, "srcref") <- NULL' (может быть, это решит проблему и для @SamR?). Спасибо за этот ответ - очень познавательно

Henrik Renlund 06.09.2024 09:02

@HenrikRenlund О да, опечатка! На самом деле я исправил это в своем коде (я проверяю код перед публикацией!), но забыл обновить сообщение.

Konrad Rudolph 06.09.2024 09:25

@SamR Думаю, вы, вероятно, уже ознакомились с определением print.function, но если вы еще этого не сделали, посмотрите также разницу между print(foo3(1)) и print(foo3(1), useSource = FALSE) (используя определение foo3, данное ОП).

Konrad Rudolph 06.09.2024 09:27

Увлекательно - так что вы могли бы сохранить определение foo3 таким же, как в версии @HenrikRenlund, и заставить R всегда печатать функции таким образом, например print.function <- function(x) print.default(x, useSource = FALSE). Или, если вы не хотите менять поведение печати всех функций, вместо установки атрибута "srcref" на NULL вы можете сделать class(fn) <- "printliteral" внутри своей функции и определить print.printliteral <- function(x) print.default(x, useSource = FALSE). Интересная штука.

SamR 06.09.2024 09:37

@KonradRudolph ой, я пропустил строчку, когда читал. Извините за этот вопрос

Carl Witthoft 06.09.2024 18:52

Другие вопросы по теме

Ошибка при передаче переменной в ggplot в пользовательской функции r
Как векторизовать функцию, которая присваивает значение элементу на основе поиска в справочной таблице?
Можно ли заменить эти две функции Python одной универсальной, принимающей либо список, либо аргумент кортежа?
Как называется событие, которое передает только аргументы типа в общую функцию в машинописном тексте?
Шифр Цезаря неправильно сдвигает буквы в алфавитном списке
Ошибка компиляции C «вызываемый объект не является функцией или указателем на функцию»
Рекурсивное преобразование фрейма данных во вложенный список, где уровень вложенности списка равен количеству столбцов в фрейме данных
PHP: обновить глобальную ссылочную переменную внутри области функции
Использование рекурсивной функции для создания списка, вложенного n раз
C++: Что означает (-1) в конце списка параметров этой функции?