2010-04-13 3 views
96

방금 ​​scoping in the R intro에 대해 읽었으며 <<- 과제에 대해 매우 궁금합니다.R에서 "<< -"(범위 지정)을 어떻게 사용합니까?

이 설명서는 <<-에 대한 하나의 (매우 흥미로운) 예를 보여주었습니다. 내가 아직도 놓치고있는 것은 이것이 유용 할 수있는 때의 맥락이다.

그렇다면 <<-의 사용이 흥미롭고 유용 할 때의 예 (또는 예제 링크)입니다. 그것을 사용하는 것의 위험성 (쉽게 풀리는 것처럼 보임)과 공유하는 느낌을 줄 수있는 팁.

답변

139

<<-은 상태를 유지하기위한 폐쇄와 함께 가장 유용합니다. 최근 광산에서 가져온 부분은 다음과 같습니다.

클로저는 다른 기능에 의해 작성된 기능입니다.클로저는 이 부모 함수의 환경 인을 포함하고 있으며 해당 함수의 모든 변수와 매개 변수에 액세스 할 수 있으므로 호출됩니다. 이는 두 가지 수준의 매개 변수를 가질 수 있기 때문에 유용합니다. 한 수준의 매개 변수 (부모)가 함수 작동 방법을 제어합니다. 다른 수준 (어린이)이 작업을 수행합니다. 다음 예는이 아이디어를 사용하여 어떻게 전력 함수 계열을 생성 할 수 있는지 보여줍니다. 부모 함수 (power)는 실제로 힘든 작업을 수행하는 하위 함수 (squarecube)를 만듭니다.

power <- function(exponent) { 
    function(x) x^exponent 
} 

square <- power(2) 
square(2) # -> [1] 4 
square(4) # -> [1] 16 

cube <- power(3) 
cube(2) # -> [1] 8 
cube(4) # -> [1] 64 

두 가지 수준에서 변수를 관리 할 수있는 기능도 가능 함수가 부모의 환경 변수를 수정 할 수 있도록하여 함수 호출을 가로 지르는 상태를 유지 할 수 있습니다. 서로 다른 레벨에서 변수를 관리하는 열쇠는 이중 화살표 할당 연산자 <<-입니다. 항상 현재 수준에서 작동하는 일반적인 단일 화살표 할당 (<-)과 달리, 이중 화살표 연산자는 부모 수준의 변수를 수정할 수 있습니다.

이렇게하면 다음 예제에서와 같이 함수가 호출 된 횟수를 기록하는 카운터를 유지 관리 할 수 ​​있습니다. new_counter이 실행될 때마다 환경을 생성하고이 환경에서 카운터 i을 초기화 한 다음 새 기능을 만듭니다.

new_counter <- function() { 
    i <- 0 
    function() { 
    # do something useful, then ... 
    i <<- i + 1 
    i 
    } 
} 

새로운 기능은 클로저이며 그 환경은 둘러싼 환경입니다. counter_onecounter_two 클로저가 실행되면 각각은 해당 환경에서 카운터를 수정 한 다음 현재 카운트를 반환합니다.

내가 (너무있을 수 있습니다 다른 경우)는 루프 내에서 (잘못)을 적용 할 때 < < 운영자가 이상하게 행동 할 것을 지적하고 싶습니다이 주제에
counter_one <- new_counter() 
counter_two <- new_counter() 

counter_one() # -> [1] 1 
counter_one() # -> [1] 2 
counter_two() # -> [1] 1 
+2

안녕하세요, Rosettacode (http://rosettacode.org/wiki/Accumulator_factory#R)의 미해결 된 R 작업입니다. –

+0

하나의 부모 함수에 두 개 이상의 클로저를 넣으시겠습니까? 난 그냥 한 조각을 시도, 그것은 마지막 폐쇄가 실행 된 것 같습니다 ... –

5

<<-을 사용하는 곳은 tcl/tk를 사용하는 간단한 GUI입니다. 몇 가지 초기 예제가 있습니다. 상태 저장을 위해 지역 변수와 전역 변수를 구별해야하기 때문입니다. 예를 들어

library(tcltk) 
demo(tkdensity) 

<<-을 사용하십시오. 그렇지 않으면 나는 마렉과 동의한다. :) - 구글 검색이 도움이된다. (당신이 TRUE에 그 함수의 inherits 매개 변수를 설정 한 경우)

5
f <- function(n, x0) {x <- x0; replicate(n, (function(){x <<- x+rnorm(1)})())} 
plot(f(1000,0),typ="l") 
+7

이것은 _not_가'<< -'을 사용하는 좋은 예입니다. 이 경우에는 for 루프가 더 명확합니다. – hadley

25

그것은 assign에 동등하게 <<- 생각하는 데 도움이됩니다. assign의 이점은 더 많은 매개 변수 (예 : 환경)를 지정할 수 있으므로 대부분 <<-보다 assign을 선호합니다.

<<-assign(x, value, inherits=TRUE)을 사용하면 "제공된 환경의 둘러싸는 환경은 변수 'x'에 도달 할 때까지 검색됩니다." 바꾸어 말하면, 그 이름을 가지는 변수를 발견 할 때까지 순서대로 환경을 계속 진행해, 그것을 할당합니다. 이것은 함수의 범위 또는 전역 환경에있을 수 있습니다.

이러한 기능이 무엇인지 이해하려면 R 환경을 이해해야합니다 (예 : search 사용).

큰 시뮬레이션을 실행하고 중간 결과를 저장하려고 할 때 정기적으로이 기능을 사용합니다. 이를 통해 주어진 함수의 범위를 벗어나는 객체를 만들거나 apply 루프를 만들 수 있습니다. 이는 매우 유용합니다. 예기치 않게 큰 루프가 종료 될 우려가있는 경우 (예 : 데이터베이스 연결 끊기),이 과정에서 모든 것을 잃을 수 있습니다. 이것은 결과가 R 환경에 저장된다는 점을 제외하고 장시간 실행되는 프로세스 중에 결과를 데이터베이스 나 파일에 쓰는 것과 같습니다.

내 기본 경고 : 글로벌 변수로 작업 중이므로 특히주의해야합니다. 특히 <<-을 사용할 때주의해야합니다. 즉, 매개 변수로 제공된 함수를 사용하려고 할 때 함수가 환경의 오브젝트 값을 사용하는 경우가 발생할 수 있습니다. 이것은 함수형 프로그래밍이 피하려고하는 주요한 것 중 하나입니다 (side effects 참조). 이 문제는 함수 내에서 사용되지 않는 고유 한 변수 이름 (설정 또는 고유 매개 변수와 함께 붙여 넣기 사용)에 값을 할당하여이 문제를 방지하지만 나중에 캐싱에 사용되며 나중에 복구해야 할 경우 - 중간 결과에 대한 분석).

+2

감사합니다. 나는 블로그를 가지고 있지만 실제로 사용하지는 않습니다. 내가 완벽한 것이 아니라면 아무것도 게시하고 싶지 않기 때문에 나는 결코 게시물을 완성 할 수 없다. 그리고 나는 그럴 시간이 없다. – Shane

+1

지혜로운 사람은 내게 말하기를 온전하게되는 것이 중요하지 않습니다. 오직 서있을뿐입니다. - 때로는 독자가 의견이있는 텍스트를 개선하는 데 도움이되는 경우가 있습니다 (블로그에서 이러한 현상이 발생합니다). 언젠가 다시 생각해 보시기 바랍니다. –

2

. 다음 코드를 감안할 때 :

fortest <- function() { 
    mySum <- 0 
    for (i in c(1, 2, 3)) { 
     mySum <<- mySum + i 
    } 
    mySum 
} 

당신이 기능은 예상 합계 6을 반환 할 것이라고 예상을하지만, 대신 생성되는 전역 변수 mySum로, 0을 반환하고 값 3을 할당 나는 완전히 할 수 없습니다 여기에 무슨 일이 일어나는지 설명해주세요. 물론 for 루프의 본문은 이 아니며이 아닌 새로운 범위 '수준'입니다. 대신, R은 fortest 함수 외부를보고, 할당 할 변수 mySum을 찾을 수 없으므로 하나를 만들고 값 1을 루프를 통해 처음으로 할당합니다. 후속 반복에서 할당의 RHS는 (변경되지 않은) 내부 mySum 변수를 참조해야하지만 LHS는 전역 변수를 참조해야합니다. 따라서 각 반복은 전역 변수의 값을 해당 반복의 값인 i으로 겹쳐 쓰므로 함수에서 빠져 나올 때 값 3을 갖습니다.

희망이 누군가를 돕는다 - 이것은 오늘 두 시간 동안 저를 곤란하게했다! (즉, < <을 <으로 바꾸면 기능이 예상대로 작동합니다.

+2

귀하의 예를 들어, 로컬'mySum' 결코 증분하지만 글로벌'mySum'. 그러므로 for 루프의 각 반복에서 전역'mySum '은'0 + i' 값을 갖습니다. 이것을'debug (fortest)'와 함께 할 수 있습니다. – clemlaflemme

+0

for-loop와 아무 관련이 없습니다. 당신은 두 가지 다른 범위를 참조하고 있습니다. 함수 내에서 지역 변수 만 업데이트하려면 함수 내에서 일관되게 모든 곳에서'<-'를 사용하십시오. – smci

+0

또는 << - everywhere @smci를 사용하십시오. 비록 전역을 피하는 것이 가장 좋습니다. –

2

<<- 연산자는 Reference Classes when writing Reference Methods에도 유용 할 수 있습니다. 예를 들면 다음과 같습니다.

myRFclass <- setRefClass(Class = "RF", 
         fields = list(A = "numeric", 
             B = "numeric", 
             C = function() A + B)) 
myRFclass$methods(show = function() cat("A =", A, "B =", B, "C =",C)) 
myRFclass$methods(changeA = function() A <<- A*B) # note the <<- 
obj1 <- myRFclass(A = 2, B = 3) 
obj1 
# A = 2 B = 3 C = 5 
obj1$changeA() 
obj1 
# A = 6 B = 3 C = 9