В чем разница между assign() и << - in R?

Обычный подход к написанию функций в R (как я понимаю) заключается в том, чтобы избежать побочных эффектов и вернуть значение из функции.

contained <- function(x) {
  x_squared <- x^2
  return(x_squared)
}

В этом случае возвращается значение, вычисленное из ввода в функцию. Но переменная x_squared недоступна.

Но если вам нужно нарушить этот базовый принцип функционального программирования (и я не уверен, насколько серьезным R является эта проблема) и вернуть объект из функции, у вас есть два варианта.

escape <- function(x){
  x_squared  <<- x^2
  assign("x_times_x", x*x, envir = .GlobalEnv)
}

Возвращаются оба объекта x_squared и x_times_x. Является ли один метод предпочтительным для другого и почему так?

Ответ 1

Томас Ламли отвечает на этот в превосходной должности в r-help на днях. <<- относится к окружению, поэтому вы можете делать что-то подобное (и снова цитирую его сообщение с 22 апреля в этом потоке):

make.accumulator<-function(){
    a <- 0
    function(x) {
        a <<- a + x
        a
    }
}

> f<-make.accumulator()
> f(1)
[1] 1
> f(1)
[1] 2
> f(11)
[1] 13
> f(11)
[1] 24

Это законное использование <<- как "супер-присвоение" с лексической областью. И не просто назначить в глобальной среде. Для этого у Тома есть такие слова выбора:

Зло и Неправильное использование - изменить переменные в глобальной среде.

Очень хороший совет.

Ответ 2

В соответствии с страницей руководства здесь,

Операторы <<- и ->> вызывают поиск в среде для определения существующего определения назначаемой переменной.

Мне никогда не приходилось делать это на практике, но, на мой взгляд, assign выигрывает много очков, чтобы точно определить среду, даже не задумываясь о правилах R-обзора. <<- выполняет поиск через среды и поэтому немного сложнее интерпретировать.

EDIT: в отношении к @Dirk и @Hadley это звучит так: assign - это подходящий способ присвоить глобальную среду (когда это то, что вы знаете, вы хотите), а <<- - это подходящий способ "поднять" до более широкой области.

Ответ 3

Как отметил @John в своем ответе, присваивание позволяет вам конкретно указать среду. Конкретное приложение будет выглядеть следующим образом:

testfn <- function(x){

    x_squared <- NULL

    escape <- function(x){
        x_squared  <<- x^2
        assign("x_times_x", x*x, envir = parent.frame(n = 1))
    }

    escape(x)

    print(x_squared)
    print(x_times_x)
}

где мы используем как <<-, так и assign. Обратите внимание, что если вы хотите использовать <<- для назначения окружению функции верхнего уровня, вам нужно объявить/инициализировать переменную. Однако с помощью assign вы можете использовать parent.frame(1) для указания инкапсулирующей среды.