Jakie są różnice między operatorami przypisania =
a <-
R?
Wiem, że operatorzy różnią się nieco, jak pokazuje ten przykład
x <- y <- 5
x = y = 5
x = y <- 5
x <- y = 5
# Error in (x <- y) = 5 : could not find function "<-<-"
Ale czy to jedyna różnica?
r
assignment-operator
r-faq
csgillespie
źródło
źródło
<-
symbolu pochodzi od starych klawiatur APL, które faktycznie miały jeden<-
klawisz.Odpowiedzi:
Jak pokazuje twój przykład
=
i<-
mają nieco inny priorytet dla operatora (który określa kolejność obliczeń, gdy są mieszane w tym samym wyrażeniu). W rzeczywistości?Syntax
w R podaje następującą tabelę pierwszeństwa operatorów, od najwyższej do najniższej:Ale czy to jedyna różnica?
Ponieważ pytałeś o operatory przypisania : tak, to jedyna różnica. Jednakże wybaczono by ci, że wierzysz inaczej. Nawet dokumentacja R
?assignOps
twierdzi, że istnieje więcej różnic:Nie podkreślmy zbyt dobrze: dokumentacja R jest (subtelnie) błędna [ 1 ] . Łatwo to pokazać: musimy po prostu znaleźć kontrprzykład
=
operatora, który nie jest (a) na najwyższym poziomie, ani (b) podwyrażenie na usztywnionej liście wyrażeń (tj{…; …}
.). - Bez ceregieli:Wyraźnie wykonaliśmy zadanie, używając
=
poza kontekstami (a) i (b). Dlaczego więc dokumentacja podstawowej funkcji języka R jest błędna przez dziesięciolecia?To dlatego, że w składni R symbol
=
ma dwa różne znaczenia, które rutynowo się łączą:=
operatora, nie wykonuje żadnych działań w czasie wykonywania, zmienia jedynie sposób, w jaki wyrażenie jest analizowane.Zobaczmy.
W dowolnym kodzie ogólnej formy…
... The
=
jest znak, który definiuje nazwany argumentem uchwala: jest to nie operator przypisania. Ponadto=
jest całkowicie zabronione w niektórych kontekstach składniowych:Każdy z nich spowoduje błąd „nieoczekiwany” = „w ‹bla›”.
W każdym innym kontekście
=
odnosi się do wywołania operatora przypisania. W szczególności samo umieszczenie nawiasów wokół podwyrażenia powoduje, że dowolne z powyższych (a) jest ważne i (b) przypisanie . Na przykład następujące zadania wykonuje przypisanie:Ale również:
Teraz możesz sprzeciwić się, że taki kod jest okropny (i możesz mieć rację). Ale wziąłem ten kod z
base::file.copy
funkcji (zastąpienie<-
z=
) - jest to wzór wszechobecne w dużej części kodzie rdzeń R.Oryginalne wyjaśnienie przez John Chambers , którego dokumentacja R jest prawdopodobnie w oparciu o właściwie wyjaśnia to poprawnie:
Wyznanie: skłamałem wcześniej. Tam jest jeden dodatkowy różnica między
=
i<-
operatorów: nazywają różne funkcje. Domyślnie te funkcje robią to samo, ale można zastąpić każdą z nich osobno, aby zmienić zachowanie. Natomiast<-
i->
(przypisanie od lewej do prawej), chociaż odrębne pod względem składniowym, zawsze wywołuje tę samą funkcję. Przesłonięcie jednego powoduje również zastąpienie drugiego. Wiedza o tym jest rzadko praktyczna, ale może być wykorzystana do zabawy z shenaniganami .źródło
?
jest w rzeczywistości pomiędzy=
i<-
, co ma ważne konsekwencje przy nadpisywaniu?
i praktycznie żadne inne.main/gram.y
) priorytet?
jest poprawnie udokumentowany i jest niższy niż zarówno, jak=
i<-
.=
otrzymają specjalne traktowanie przed zbudowaniem parsowania. Być może związane z argumentami funkcji, ma sens,foo(x = a ? b)
że szukamy=
przed analizą reszty wyrażenia.Różnica między operatorami przypisania jest wyraźniejsza, gdy używasz ich do ustawiania wartości argumentu w wywołaniu funkcji. Na przykład:
W takim przypadku
x
jest deklarowany w ramach funkcji, więc nie istnieje w obszarze roboczym użytkownika.W takim przypadku
x
jest zadeklarowany w obszarze roboczym użytkownika, dzięki czemu można go używać po zakończeniu wywołania funkcji.Istnieje ogólna preferencja wśród społeczności R, aby używać
<-
przypisania (innego niż w sygnaturach funkcji) dla zgodności z (bardzo) starymi wersjami S-Plus. Pamiętaj, że spacje pomagają wyjaśnić sytuacje takie jakWiększość R IDE ma skróty klawiaturowe, aby
<-
ułatwić pisanie. Ctrl+ =w Architect, Alt+ -w RStudio ( Option+ -pod macOS), Shift+ -(podkreślenie) w emacs + ESS.Jeśli wolisz pisać
=
, aby<-
jednak móc korzystać z bardziej wspólny symbol przypisania dla kodu publicznie wydany (na CRAN, na przykład), a następnie można użyć jednej ztidy_*
funkcji wformatR
pakiecie, aby automatycznie zastąpić=
z<-
.Odpowiedź na pytanie „Dlaczego
x <- y = 5
zgłasza błąd, ale niex <- y <- 5
?” to „To zależy od magii zawartej w parserze”. Składnia R zawiera wiele niejednoznacznych przypadków , które należy rozwiązać w ten czy inny sposób. Analizator składni wybiera rozstrzyganie bitów wyrażenia w różnych porządkach w zależności od tego,=
czy<-
zostało użyte.Aby zrozumieć, co się dzieje, musisz wiedzieć, że przypisanie po cichu zwraca przypisaną wartość. Możesz to zobaczyć wyraźniej, na przykład poprzez wyraźne drukowanie
print(x <- 2 + 3)
.Po drugie, jest wyraźniej, jeśli do przypisania użyjemy notacji przedrostkowej. Więc
Analizator składni interpretuje
x <- y <- 5
jakoMożemy spodziewać się, że
x <- y = 5
będzie wówczasale tak naprawdę jest interpretowane jako
Jest tak, ponieważ
=
ma niższy priorytet niż<-
, jak pokazano na stronie?Syntax
pomocy.źródło
median((x = 1:10))
ten sam efekt comedian(x <- 1:10)
.x <- x = 5
jest interpretowane, jest nieco błędne: w rzeczywistości R interpretuje to jako`<-<-`(x, y = 5, value = 5)
(co samo w sobie jest mniej więcej równoważnetmp <- x; x <- `<-<-`(tmp, y = 5, value = 5)
). Yikes!=
w jaki używasz w wywołaniu funkcji , nie wykonuje przypisania i nie jest operatorem przypisania. Jest to całkowicie odrębne sparsowane wyrażenie R, które akurat używa tego samego znaku. Ponadto wyświetlany kod nie „deklaruje”x
w zakresie funkcji. W deklaracji funkcji wykonuje powiedział oświadczenie. Wywołanie funkcji nie działa (staje się nieco bardziej skomplikowane w przypadku nazwanych...
argumentów).Przewodnik po stylu R firmy Google upraszcza ten problem, zakazując przypisania „=”. Niezły wybór.
https://google.github.io/styleguide/Rguide.xml
Instrukcja R zawiera szczegółowy opis wszystkich 5 operatorów przypisania.
http://stat.ethz.ch/R-manual/R-pched/library/base/html/assignOps.html
źródło
x<-y
kiedyx < -y
miał na myśli, denerwuje mnie tak bardzo, że osobiście wolę=
. Uzależnienie twojego kodu od obecności białych znaków nie wydaje mi się dobre. Można sugerować odstępy jako porady dotyczące stylu, ale aby kod działał inaczej, niezależnie od tego, czy jest tam spacja, czy nie? Co się stanie, jeśli sformatujesz kod lub użyjesz funkcji wyszukiwania i zamiany, białe znaki mogą czasem zniknąć, a kod nie działa. To nie jest problem=
. IIUC, zakaz=
jest równoznaczny z wymaganiem „<-
”; tj. 3 znaki łącznie ze spacją, nie tylko „<-
”.TRUE
pod uwagę przez R. Więc jeśli zamierzasz sprawdzić, czyx
jest mniejszy-y
, możesz napisać,if (x<-y)
który nie będzie ostrzegał ani nie popełnił błędu, i wydaje się, że działa dobrze. Ale tylkoFALSE
wtedyy=0
.=
i używasz<-
, trudno argumentować, że dodatkowy krokgrep "[^<]<-[^ ]" *.R
nie jest potrzebny.=
nie potrzebuje takiegogrep
.<-
jeśli możesz użyć=
? W 99,99% przypadków=
jest w porządku. Czasem jednak potrzebujesz<<-
innej historii.x = y = 5
jest równoważnex = (y = 5)
, ponieważ operatory przypisania „grupują” od prawej do lewej, co działa. Znaczenie: przypisz 5 doy
, pozostawiając cyfrę 5; a następnie przypisz 5 dox
.To nie to samo
(x = y) = 5
, co nie działa! Znaczenie: przypisz wartośćy
dox
, pozostawiając wartośćy
; a następnie przypisz 5 do, umm ..., co dokładnie?Po zmieszaniu różnych rodzajów operatorów przypisania
<-
wiąże się mocniej niż=
. Takx = y <- 5
jest interpretowane jakox = (y <- 5)
, co ma sens.Niestety
x <- y = 5
jest interpretowany jako(x <- y) = 5
, co jest przypadkiem, który nie działa!Zobacz
?Syntax
i?assignOps
dla pierwszeństwa (wiązanie) i grupowania reguł.źródło
<- <<-
znajduje się powyżej=
tabeli pierwszeństwa, co oznacza, że<-
zostanie ona wykonana jako pierwsza. Tak więcx <- y = 5
należy wykonać jako(x <- y) = 5
.Według Johna Chambersa operator
=
jest dozwolony tylko na „najwyższym poziomie”, co oznacza, że nie jest dozwolony w strukturach kontrolnych takich jakif
, co powoduje, że następujący błąd programowania jest nielegalny.Jak pisze: „Odrzucenie nowego formularza przypisania [=] w wyrażeniach kontrolnych pozwala uniknąć błędów programistycznych (takich jak powyższy przykład), które są bardziej prawdopodobne w przypadku równego operatora niż w przypadku innych przypisań S.”
Możesz to zrobić, jeśli jest „odizolowany od otaczającej struktury logicznej za pomocą nawiasów klamrowych lub dodatkowej pary nawiasów”, więc
if ((x = 0)) 1 else x
działałoby.Zobacz http://developer.r-project.org/equalAssign.html
źródło
x==0
prawie zawsze ma na myśli.x=0
jako zadaniex<-0
!=
jak najmniej, ponieważ=
i==
wyglądam tak podobnie.if(x = 0) 1 else x
zgłasza błąd, pomagając mi znaleźć i naprawić błąd.if(x <- 1) 1 else x
nie zgłasza błędu i jest bardzo mylące.else
wartość, czy chciałeś napisać ją w ten sposób?”, Ale może to być marzenie o fajce…Operatory
<-
i=
przypisują do środowiska, w którym są oceniane. Operator<-
może być używany w dowolnym miejscu, podczas gdy operator=
jest dozwolony tylko na najwyższym poziomie (np. W pełnym wyrażeniu wpisanym w wierszu polecenia) lub jako jedno z podwyrażeń na usztywnionej liście wyrażeń.źródło
x <- 42
w sobie jest stwierdzeniem; wif (x <- 42) {}
byłoby wyrazem, a nie jest ważny. Żeby było jasne, nie ma to nic wspólnego z tym, czy jesteś w środowisku globalnym, czy nie.1 + (x = 2)
function() x = 1
,repeat x = 1
,if (TRUE) x = 1
....Może to również przyczynić się do zrozumienia różnicy między tymi dwoma operatorami:
Dla pierwszego elementu R przypisał wartości i prawidłową nazwę, natomiast nazwa drugiego elementu wygląda nieco dziwnie.
Wersja R 3.3.2 (31.10.2016); macOS Sierra 10.12.1
źródło
data.frame
próbuje użyć nazwy podanej zmiennej jako nazwy elementu w ramce danych)make.names("b <- rnorm(10)")
.