R устанавливает новое значение в качестве аргумента по умолчанию для функции - PullRequest
0 голосов
/ 15 октября 2018

Я написал функцию в R следующим образом:

foo <- function(a, b = 1) {
    ...
}

Но теперь я хочу изменить аргумент по умолчанию b, например:

foo(b = 2)

Это функцияв принципе.Но R не позволяет этого, что приводит меня к ошибке.

Как это исправить?

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Ваш код в foo(b = 2) является приложением функции: если все работает как положено, он даст вам значение, а не функцию.

Вы можете изменить значения аргументов по умолчанию, используя formals:

foo <- function(a, b = 1) {
  a + b
}

formals(foo)$b <- 2
foo
#function (a, b = 2) 
# {
#     a + b
# }

Если вы не хотите изменять foo напрямую, есть несколько вариантов:

1) Сначала скопируйте, потом измените

foa <- foo
formals(foa)$b <- 42

ОдинМожно подумать об использовании "formals<-" в качестве ярлыка, но это может быть сложно, поскольку вам нужно предоставить полный список аргументов (используя alist вместо list, поскольку первый может принимать пустой аргумент):

"formals<-"(foo, , list(b=2))  # trying it with `list` 
function (b = 2)  # we lost one argument! 
{
    a + b
} 
"formals<-"(foo, , alist(a=, b=42))  # this one is better!
function (a, b = 42) 
{
  a + b
}

2) Используйте purr::partial или function(a) foo(a,b=42), как рекомендовано в другом ответе.

3) И третий способ ... на самом деле можно написать очень простую функцию (я назову ее p2), которая изменяет некоторые аргументов по умолчанию функции ивозвращает измененную функцию:

p2 <- function(f, l){
  formals(f)[names(l)] <- l
  f
}

p2(foo, list(b=42)) # changing a default: function (a, b = 42) a+b
p2(foo, alist(b=)) # removing a default: function (a, b) a+b
p2(foo, list(c="bingo") # adding an argument: function (a, b = 2, c = "bingo") a+b

Измененную версию:

p3 <- function(f, ...){
  l <- as.list(sys.call())[-(1L:2L)]  # code from `alist`
  formals(f)[names(l)] <- l
  f
  }

Теперь использование становится короче:

p3(foo, b=43) # function (a, b = 43) a+b
p3(foo, b=) # function(a,b) a+b

Обратите внимание, что p2 и p3 не будет работать должным образом с общими функциями, такими как mean и min.Вероятно, это причина того, что код в purrr:partial намного сложнее.

0 голосов
/ 15 октября 2018

Вы можете вызвать foo следующим образом: foo(a, b = whatever)

Если вам нужно действительно часто менять значение по умолчанию b на одно и то же значение, вы можете создать новую функцию, связанную с foo.

Вы можете либо определить новую функцию:

# partially substitute in a `b` value
goo <- purrr::partial(foo, b = 2, .first = FALSE)

# or, a bit more explicitly,
hoo <- function(a) {foo(a, b = 2)}

, либо создать конструктор функций / factory , который позволит вам создать столько функций, связанных с foo, сколько выкак

foo_builder <- function(b = 1) {
  function(a) {
    # your definition of foo goes here
    blah <- blah_f(a, b)
  }
}

Теперь вы можете передать значение b в foo_builder, и оно вернет эквивалентную функцию в foo(a, b = whatever_you_passed_to_foo_builder)

goo <- foo_builder(2)
goo(a = ...)

Например,

foo_builder <- function(b = 1){
   function(a){
     message(b)
     a + b
   }
 }

Теперь, когда внутренняя функция определена foo_builder, она принимает значение b, доступное для среды foo_builder.По умолчанию это 1, но его можно изменить.

Например,

# default
foo_builder()(1)
1
[1] 2

# with b=2 in the closure returned by foo_builder
b <- 2
fb <- foo_builder(b)
fb(1)
2
[1] 3

Комментатор предложил, чтобы вы выполняли принудительное вычисление b при выполнении замыканий таким образом;из-за следующего:

b <- 2
fb <- foo_builder(b)
b <- 3
fb(1)
# 3
# [1] 4

Так что, возможно, перепишите foo_builder:

foo_builder <- function(b = 1){
   force(b)
   function(a){
     message(b)
     a + b
   }
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...