Apa perbedaan antara operator penugasan “=” dan “<-” dalam R?

712

Apa perbedaan antara operator penugasan =dan <-dalam R?

Saya tahu bahwa operator sedikit berbeda, seperti yang ditunjukkan contoh ini

x <- y <- 5
x = y = 5
x = y <- 5
x <- y = 5
# Error in (x <- y) = 5 : could not find function "<-<-"

Tetapi apakah ini satu-satunya perbedaan?

csgillespie
sumber
45
Seperti disebutkan di sini , asal mula <-simbol berasal dari keyboard APL lama yang sebenarnya memiliki satu <-kunci saja.
joran

Jawaban:

97

Apa perbedaan antara operator penugasan =dan <-dalam R?

Seperti yang ditunjukkan contoh Anda, =dan <-memiliki prioritas operator yang sedikit berbeda (yang menentukan urutan evaluasi ketika mereka dicampur dalam ekspresi yang sama). Bahkan, ?Syntaxdalam R memberikan tabel prioritas operator berikut, dari tertinggi ke terendah:

…
‘-> ->>’           rightwards assignment
‘<- <<-’           assignment (right to left)=’                assignment (right to left)

Tetapi apakah ini satu-satunya perbedaan?

Karena Anda bertanya tentang operator penugasan : ya, itulah satu-satunya perbedaan. Namun, Anda akan dimaafkan karena percaya sebaliknya. Bahkan dokumentasi R dari ?assignOpsklaim bahwa ada lebih banyak perbedaan:

Operator <-dapat digunakan di mana saja, sedangkan operator =hanya diperbolehkan di tingkat atas (misalnya, dalam ekspresi lengkap yang diketik di command prompt) atau sebagai salah satu subekspresi dalam daftar ekspresi yang diperkuat.

Jangan terlalu menekankan hal itu: dokumentasi R (secara halus) salah [ 1 ] . Ini mudah ditunjukkan: kita hanya perlu menemukan contoh tandingan dari =operator yang tidak (a) di tingkat atas, atau (b) subekspresi dalam daftar ekspresi yang diperkuat (yaitu {…; …}). - Tanpa basa-basi:

x
# Error: object 'x' not found
sum((x = 1), 2)
# [1] 3
x
# [1] 1

Jelas kami telah melakukan tugas, menggunakan =, di luar konteks (a) dan (b). Jadi, mengapa dokumentasi fitur bahasa R inti salah selama beberapa dekade?

Itu karena dalam sintaks R simbol =memiliki dua makna berbeda yang secara rutin digabungkan:

  1. Arti pertama adalah sebagai operator penugasan . Ini semua yang kita bicarakan sejauh ini.
  2. Arti kedua bukanlah operator melainkan token sintaksis yang memberi sinyal argumen bernama lewat dalam panggilan fungsi. Tidak seperti =operator yang tidak melakukan tindakan saat runtime, itu hanya mengubah cara ekspresi diurai.

Ayo lihat.

Dalam bentuk kode apa pun dari bentuk umum ...

‹function_name›(‹argname› = ‹value›,)
‹function_name›(‹args›, ‹argname› = ‹value›,)

… The =adalah token yang mendefinisikan lewat argumen: itu bukan operator penugasan. Lebih jauh lagi, =sepenuhnya dilarang dalam beberapa konteks sintaksis:

if (‹var› = ‹value›) …
while (‹var› = ‹value›) …
for (‹var› = ‹value› in ‹value2›) …
for (‹var1› in ‹var2› = ‹value›) …

Semua ini akan menimbulkan kesalahan “tak terduga '=' di ‹bla›”.

Dalam konteks lain, =merujuk pada panggilan operator penugasan. Secara khusus, hanya menempatkan tanda kurung di sekitar subekspresi membuat salah satu dari yang di atas (a) valid, dan (b) tugas . Misalnya, berikut ini melakukan tugas:

median((x = 1 : 10))

Tetapi juga:

if (! (nf = length(from))) return()

Sekarang Anda mungkin keberatan bahwa kode seperti itu mengerikan (dan Anda mungkin benar). Tapi saya mengambil kode ini dari base::file.copyfungsi (ganti <-dengan =) - ini adalah pola meresap di banyak basis kode R inti.

The penjelasan asli oleh John Chambers , yang dokumentasi R yang mungkin didasarkan pada, sebenarnya menjelaskan ini dengan benar:

[ =penugasan] diizinkan hanya di dua tempat dalam tata bahasa: di tingkat atas (sebagai program lengkap atau ungkapan yang diketik pengguna); dan ketika terisolasi dari struktur logis sekitarnya, dengan kawat gigi atau sepasang kurung tambahan.


Sebuah pengakuan: Saya berbohong sebelumnya. Ada adalah satu perbedaan tambahan antara =dan <-operator: mereka memanggil fungsi-fungsi yang berbeda. Secara default fungsi-fungsi ini melakukan hal yang sama tetapi Anda dapat menimpa keduanya secara terpisah untuk mengubah perilaku. Sebaliknya, <-dan ->(tugas dari kiri ke kanan), meskipun secara sintaksis berbeda, selalu memanggil fungsi yang sama . Mengesampingkan satu juga mengesampingkan yang lain. Mengetahui hal ini jarang praktis tetapi dapat digunakan untuk beberapa shenanigans yang menyenangkan .

Konrad Rudolph
sumber
1
Tentang prioritas, dan kesalahan dalam dokumen R, prioritas ?sebenarnya ada di antara =dan <-, yang memiliki konsekuensi penting ketika mengesampingkan ? , dan hampir tidak ada yang sebaliknya.
Moody_Mudskipper
@Moody_Mudskipper itu aneh! Anda tampaknya benar, tetapi menurut kode sumber ( main/gram.y), prioritas ?didokumentasikan dengan benar, dan lebih rendah dari keduanya =dan <-.
Konrad Rudolph
Saya tidak berbicara C tetapi saya kira itu =mendapatkan perlakuan khusus sebelum pohon parse dibangun. Mungkin terkait dengan argumen fungsi, masuk akal bahwa foo(x = a ? b)kita akan mencari =sebelum menguraikan sisa ekspresi.
Moody_Mudskipper
@Moody_Mudskipper Saya sudah bertanya r-devel
Konrad Rudolph
2
@Moody_Mudskipper FWIW ini akhirnya diperbaiki di 4.0.0.
Konrad Rudolph
661

Perbedaan dalam operator penugasan lebih jelas ketika Anda menggunakannya untuk menetapkan nilai argumen dalam panggilan fungsi. Sebagai contoh:

median(x = 1:10)
x   
## Error: object 'x' not found

Dalam hal ini, xdinyatakan dalam lingkup fungsi, sehingga tidak ada di ruang kerja pengguna.

median(x <- 1:10)
x    
## [1]  1  2  3  4  5  6  7  8  9 10

Dalam hal ini, xdideklarasikan di ruang kerja pengguna, sehingga Anda dapat menggunakannya setelah pemanggilan fungsi selesai.


Ada preferensi umum di antara komunitas R untuk menggunakan <-untuk penugasan (selain dari pada tanda tangan fungsi) untuk kompatibilitas dengan (sangat) versi lama S-Plus. Perhatikan bahwa spasi membantu menjelaskan situasi seperti

x<-3
# Does this mean assignment?
x <- 3
# Or less than?
x < -3

Sebagian besar R IDE memiliki pintasan keyboard untuk <-memudahkan mengetik. Ctrl+ =di Arsitek, Alt+ -di RStudio ( Option+ di -bawah macOS), Shift+ -(garis bawah) di emacs + ESS.


Jika Anda lebih suka menulis =untuk <-namun ingin menggunakan simbol tugas yang lebih umum untuk kode dirilis ke publik (di CRAN, misalnya), maka Anda dapat menggunakan salah satu tidy_*fungsi dalam formatRpaket secara otomatis mengganti =dengan <-.

library(formatR)
tidy_source(text = "x=1:5", arrow = TRUE)
## x <- 1:5

Jawaban untuk pertanyaan "Mengapa x <- y = 5melempar kesalahan tetapi tidak x <- y <- 5?" adalah "Ini ke sihir yang terkandung dalam parser". Sintaks R berisi banyak kasus ambigu yang harus diselesaikan dengan satu atau lain cara. Parser memilih untuk menyelesaikan bit ekspresi dalam urutan berbeda tergantung pada apakah =atau <-tidak digunakan.

Untuk memahami apa yang terjadi, Anda perlu tahu bahwa tugas secara diam-diam mengembalikan nilai yang ditugaskan. Anda dapat melihatnya lebih jelas dengan mencetak secara eksplisit, misalnya print(x <- 2 + 3).

Kedua, lebih jelas jika kita menggunakan notasi awalan untuk penugasan. Begitu

x <- 5
`<-`(x, 5)  #same thing

y = 5
`=`(y, 5)   #also the same thing

Parser mengartikan x <- y <- 5sebagai

`<-`(x, `<-`(y, 5))

Kita mungkin berharap itu x <- y = 5akan terjadi

`<-`(x, `=`(y, 5))

tetapi sebenarnya itu akan ditafsirkan sebagai

`=`(`<-`(x, y), 5)

Ini karena =lebih diutamakan daripada <-, seperti yang ditunjukkan pada ?Syntaxhalaman bantuan.

Richie Cotton
sumber
4
Ini juga disebutkan dalam bab 8.2.26 dari The R Inferno oleh Patrick Burns ( Lagi pula saya bukan sebuah rekomendasi)
Uwe
3
Namun, median((x = 1:10))memiliki efek yang sama dengan median(x <- 1:10).
Francesco Napolitano
2
saya benar-benar tidak menganggapnya pintasan, dalam hal apa pun Anda menekan jumlah tombol yang sama
yosemite_k
5
Saya baru menyadari bahwa penjelasan Anda tentang bagaimana x <- x = 5ditafsirkan sedikit salah: Pada kenyataannya, R menafsirkannya sebagai ​`<-<-`(x, y = 5, value = 5)(yang itu sendiri kurang lebih setara dengan tmp <- x; x <- `<-<-`(tmp, y = 5, value = 5)). Astaga!
Konrad Rudolph
4
... Dan saya baru menyadari bahwa bagian pertama dari jawaban ini salah dan, sayangnya, cukup menyesatkan karena melanggengkan kesalahpahaman umum: Cara Anda menggunakan =panggilan fungsi tidak melakukan penugasan , dan bukan operator penugasan. Ini adalah ekspresi R yang diuraikan sepenuhnya berbeda, yang kebetulan menggunakan karakter yang sama. Lebih lanjut, kode yang Anda tunjukkan tidak “menyatakan” xdalam lingkup fungsi. The deklarasi fungsi Melakukan kata deklarasi. Panggilan fungsi tidak (itu menjadi sedikit lebih rumit dengan ...argumen bernama ).
Konrad Rudolph
103

Panduan gaya R Google menyederhanakan masalah dengan melarang "=" untuk penugasan. Bukan pilihan yang buruk.

https://google.github.io/styleguide/Rguide.xml

Manual R menjelaskan secara rinci semua 5 operator penugasan.

http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html

Nosredna
sumber
133
Kelemahan dari penugasan tidak disengaja pada x<-ysaat x < -yitu dimaksudkan, membuat saya sangat kesal yang secara pribadi saya sukai =. Memiliki kode Anda bergantung pada spasi yang ada tampaknya tidak baik bagi saya. Tidak masalah untuk menyarankan spasi sebagai saran gaya tetapi untuk kode Anda berjalan berbeda apakah ada ruang di sana atau tidak? Bagaimana jika Anda memformat ulang kode Anda, atau menggunakan pencarian dan ganti, spasi putih kadang-kadang bisa hilang dan kode menjadi serba salah. Itu tidak masalah =. IIUC, melarang =sama dengan membutuhkan " <- "; yaitu, 3 karakter termasuk spasi, bukan hanya " <-".
Matt Dowle
12
Perhatikan bahwa non-0 dianggap TRUEoleh R. Jadi jika Anda bermaksud menguji jika xkurang dari -y, Anda dapat menulis if (x<-y)yang tidak akan memperingatkan atau kesalahan, dan tampaknya berfungsi dengan baik. Tapi itu hanya akan FALSEkapan y=0.
Matt Dowle
4
Jika Anda memang melarang =dan menggunakannya <- maka sulit untuk membantah bahwa langkah tambahan grep "[^<]<-[^ ]" *.Rtidak diperlukan. =tidak perlu seperti itu grep.
Matt Dowle
34
Mengapa melukai mata dan jari <-Anda jika Anda bisa menggunakannya =? Dalam 99,99% kali =tidak masalah. Kadang-kadang Anda membutuhkannya <<-, yang merupakan sejarah yang berbeda.
Fernando
10
Fokus pada <- mungkin merupakan salah satu alasan lemah karena kurangnya + = dan - =.
Chris
37

x = y = 5setara dengan x = (y = 5), karena operator penugasan "grup" kanan ke kiri, yang berfungsi. Artinya: menugaskan 5 ke y, meninggalkan nomor 5; dan kemudian menetapkan bahwa 5 untuk x.

Ini tidak sama dengan (x = y) = 5, yang tidak berfungsi! Artinya: tetapkan nilai yuntuk x, meninggalkan nilai y; dan kemudian menetapkan 5 untuk, umm ..., apa sebenarnya?

Saat Anda mencampur berbagai jenis operator penugasan, <-ikat lebih ketat dari =. Jadi x = y <- 5diartikan sebagai x = (y <- 5), yang merupakan kasus yang masuk akal.

Sayangnya, x <- y = 5ditafsirkan sebagai (x <- y) = 5, yang merupakan kasus yang tidak berhasil!

Lihat ?Syntaxdan ?assignOpsuntuk aturan prioritas (mengikat) dan pengelompokan.

Steve Pitchers
sumber
Ya, seperti yang dikatakan Konrad Rudolph di <- <<-atas = dalam tabel diutamakan, yang berarti <-akan ditentukan terlebih dahulu. Jadi, x <- y = 5harus dieksekusi sebagai (x <- y) = 5.
Nick Dong
1
@Nick Dong Ya. Bermanfaat, tabel prioritas operator didokumentasikan secara jelas dalam ? Sintaks {basis} .
Steve Pitchers
33

Menurut John Chambers, operator =hanya diperbolehkan di "tingkat atas," yang berarti tidak diperbolehkan dalam struktur kontrol seperti if, membuat kesalahan pemrograman berikut ini ilegal.

> if(x = 0) 1 else x
Error: syntax error

Saat ia menulis, "Menolak formulir penugasan baru [=] dalam ekspresi kontrol menghindari kesalahan pemrograman (seperti contoh di atas) yang lebih mungkin dengan operator yang sama daripada dengan penugasan S lainnya."

Anda dapat melakukan ini jika "terisolasi dari struktur logis sekitarnya, dengan kawat gigi atau sepasang kurung tambahan," demikian juga if ((x = 0)) 1 else xakan berhasil.

Lihat http://developer.r-project.org/equalAssign.html

Aaron meninggalkan Stack Overflow
sumber
11
Itu adalah bug umum, x==0hampir selalu berarti sebaliknya.
Aaron meninggalkan Stack Overflow
14
Ah, ya, saya lupa bahwa Anda mengatakan "kesalahan pemrograman". Sebenarnya ini adalah kabar baik bahwa ini menyebabkan kesalahan. Dan alasan yang baik untuk memilih x=0sebagai tugas berakhir x<-0!
Steve Pitchers
7
Ya, itu baik bahwa ini menyebabkan kesalahan, meskipun saya menarik pelajaran berbeda tentang apa yang harus dipilih; Saya memilih untuk menggunakan =sesedikit mungkin karena =dan ==terlihat sangat mirip.
Aaron meninggalkan Stack Overflow
2
Cara contoh ini disajikan sangat aneh bagi saya. if(x = 0) 1 else xmelempar kesalahan, membantu saya menemukan dan memperbaiki bug. if(x <- 1) 1 else xtidak melempar kesalahan dan sangat membingungkan.
Gregor Thomas
3
Maksud saya, pemeriksa kesalahan yang sangat membantu akan melemparkan kesalahan di sana dan berkata "Anda memiliki kode tidak berguna yang akan selalu mengembalikan elsenilai, apakah Anda bermaksud menulis seperti itu?", Tetapi, itu mungkin mimpi pipa ...
TylerH
26

Operator <-dan =menugaskan ke lingkungan di mana mereka dievaluasi. Operator <-dapat digunakan di mana saja, sedangkan operator =hanya diperbolehkan di tingkat atas (misalnya, dalam ekspresi lengkap yang diketik di command prompt) atau sebagai salah satu subekspresi dalam daftar ekspresi yang diperkuat.

Haim Evgi
sumber
8
Saya pikir "tingkat atas" berarti pada tingkat pernyataan, bukan tingkat ekspresi. Jadi x <- 42dengan sendirinya adalah pernyataan; di if (x <- 42) {}dalamnya akan menjadi ekspresi, dan tidak valid. Agar jelas, ini tidak ada hubungannya dengan apakah Anda berada di lingkungan global atau tidak.
Steve Pitchers
1
Ini: "operator = hanya diizinkan di tingkat atas" adalah kesalahpahaman yang banyak diterima dan sepenuhnya salah.
Konrad Rudolph
Ini tidak benar - misalnya, ini berfungsi, meskipun penugasan bukan ekspresi lengkap:1 + (x = 2)
Pavel Minaev
1
Untuk mengklarifikasi komentar oleh KonradRudolph dan PavelMinaev, saya pikir terlalu kuat untuk mengatakan bahwa itu sepenuhnya salah, tetapi ada pengecualian, yaitu ketika "terisolasi dari struktur logis sekitarnya, dengan kawat gigi atau sepasang kurung tambahan."
Aaron meninggalkan Stack Overflow
Atau di function() x = 1, repeat x = 1, if (TRUE) x = 1....
Moody_Mudskipper
6

Ini juga dapat menambah pemahaman tentang perbedaan antara kedua operator:

df <- data.frame(
      a = rnorm(10),
      b <- rnorm(10)
)

Untuk elemen pertama R telah menetapkan nilai dan nama yang tepat, sedangkan nama elemen kedua terlihat agak aneh.

str(df)
# 'data.frame': 10 obs. of  2 variables:
#  $ a             : num  0.6393 1.125 -1.2514 0.0729 -1.3292 ...
#  $ b....rnorm.10.: num  0.2485 0.0391 -1.6532 -0.3366 1.1951 ...

R versi 3.3.2 (2016-10-31); macOS Sierra 10.12.1

Denis Rasulev
sumber
6
dapatkah Anda memberikan penjelasan yang lebih terperinci tentang mengapa ini terjadi / apa yang terjadi di sini? (petunjuk: data.framemencoba menggunakan nama variabel yang disediakan sebagai nama elemen dalam bingkai data)
Ben Bolker
Bayangkan saja, mungkinkah ini bug? Dan jika demikian, bagaimana dan di mana saya melaporkannya?
Denis Rasulev
7
itu bukan bug. Saya mencoba mengisyaratkan jawaban dalam komentar saya di atas. Saat mengatur nama elemen, R akan menggunakan yang setara dengan make.names("b <- rnorm(10)").
Ben Bolker