x
że jest wewnątrz funkcji anonimowej jest niex
w środowisko globalne (twoja przestrzeń robocza). Jest to kopia x
, lokalna dla anonimowej funkcji. Nie jest tak łatwo powiedzieć, że R kopiuje obiekty w wywołaniach funkcji; R będzie dążyć do tego, aby nie kopiować, jeśli potrafi, chociaż po modyfikacji czegoś R musi skopiować obiekt.
Jak @DWin zwraca uwagę, to skopiowana wersja x
który został zmodyfikowany jest zwrócony przez wywołanie sapply()
Twój twierdził wyjście nie jest to, co mam:
> x <- c(1:10)
> print(x)
[1] 1 2 3 4 5 6 7 8 9 10
> sapply(1:10,function(i){
+ x[i] = 4
+ })
[1] 4 4 4 4 4 4 4 4 4 4
> print(x)
[1] 1 2 3 4 5 6 7 8 9 10
Oczywiste jest, że kod nie prawie co myślałeś, że to zrobi. Problem polega na tym, że dane wyjściowe z sapply()
nie zostały przypisane do obiektu, a zatem są drukowane, a tym samym odrzucane.
Powód, dla którego kod działa, wynika również z reguł określania zakresu R. Naprawdę powinieneś przekazać funkcję jako argumenty do obiektów, których funkcja potrzebuje. Jeśli jednak R może: t znaleźć obiekt lokalny dla funkcji, przeszuka środowisko nadrzędne dla obiektu pasującego do nazwy, a następnie, jeśli to właściwe, elementu nadrzędnego tego środowiska, ostatecznie trafiając do środowiska globalnego, do przestrzeni roboczej. Twój kod działa, ponieważ w końcu znalazł x
do pracy, ale został natychmiast skopiowany, kopia ta została zwrócona na końcu wywołania sapply()
.
To kopiowanie zajmuje dużo czasu i pamięci w wielu przypadkach. Jest to jeden z powodów, dla których ludzie myślą, że pętle for
są wolne w R; nie przypisują pamięci dla obiektu przed wypełnieniem go pętlą. Jeśli nie przydzielisz pamięci, R musi zmodyfikować/skopiować obiekt, aby dodać następny wynik pętli.
Ponownie jednak, że nie zawsze jest to takie proste, wszędzie w badania, na przykład ze środowiskami, gdzie kopią środowisku tak naprawdę odnosi się do wersji oryginalnej:
> a <- new.env()
> a
<environment: 0x1af2ee0>
> b <- 4
> assign("b", b, env = a)
> a$b
[1] 4
> c <- a ## copy the environment to `c`
> assign("b", 7, env = c) ## assign something to `b` in env `c`
> c$b ## as expected
[1] 7
> a$b ## also changed `b` in `a` as `a` and `c` are actually the same thing
[1] 7
Jeśli rozumiesz te rodzaje rzeczy, czytając podręcznik R Language Definition, który zawiera wiele szczegółów tego, co dzieje się pod maską w R.
Dzięki! Ale dlaczego nie pisać takiego kodu w R? Czy istnieje jakieś potencjalne ryzyko lub zwykła konwencja? Myślę, że normalne jest modyfikowanie obiektów globalnych w funkcji w innych językach. –
W językach funkcyjnych funkcje nie mogą mieć skutków ubocznych. R nie jest tak ścisły, ale nadal jest prawdą, że funkcje R ograniczają efekty uboczne. Lepiej pracować tak, jak zamierzano, niż próbować pisać tak, jakbyś pisał w innym języku. Istnieje kilka systemów obiektowych (S3, S4, klasy referencyjne). S3 jest najczęściej używany. S4 jest znacznie bardziej złożony. Klasy referencyjne są ostatnim dodatkiem. Możesz w szczególności zapoznać się z klasami referencyjnymi. Istnieją również pakiety dostarczane przez użytkowników, które oferują różne paradygmaty: proto i R.oo (i prawdopodobnie inne). –
@Spirit Plus można użyć 'parent.frame (3)' zamiast '.GlobalEnv' do przechowywania x w zamknięciu, w którym został uruchomiony sapply, co byłoby znacznie bezpieczniejsze. (Dlaczego 3? 1-anonimowa ramka funkcyjna, 2-sapply frame, 3-sapply enclosure) – mbq