Rの代入演算子=
と<-
の違いは何ですか?
この例が示すように、演算子がわずかに異なることを私は知っています
x <- y <- 5
x = y = 5
x = y <- 5
x <- y = 5
# Error in (x <- y) = 5 : could not find function "<-<-"
しかし、これだけの違いはありますか?
代入演算子 の違いは、関数呼び出しで引数値を設定するためにそれらを使用すると、より明確になります。例えば:
median(x = 1:10)
x
## Error: object 'x' not found
この場合、x
は関数の有効範囲内で宣言されているため、ユーザーワークスペースには存在しません。
median(x <- 1:10)
x
## [1] 1 2 3 4 5 6 7 8 9 10
この場合、x
はユーザーワークスペースで宣言されているので、関数呼び出しが完了した後で使用できます。
Rコミュニティの間では、(非常に)古いバージョンのS-Plusとの互換性のために(関数シグネチャ以外で)代入に<-
を使うことが一般的に好まれています。スペースは、次のような状況を明確にするのに役立ちます。
x<-3
# Does this mean assignment?
x <- 3
# Or less than?
x < -3
ほとんどのR IDEには、<-
を入力しやすくするためのキーボードショートカットがあります。 Ctrl + = 建築家では、 Alt + - RStudioで(Option + - macOSの下) Shift + - emacs + ESSでは(アンダースコア)。
もしあなたが=
を<-
に書くことを好むが(例えばCRAN上で)一般に公開されたコードにもっと一般的な代入記号を使いたいのなら、formatR
パッケージの tidy_*
関数の1つを使うことができます。 =
を<-
に置き換えます。
library(formatR)
tidy_source(text = "x=1:5", arrow = TRUE)
## x <- 1:5
「x <- y = 5
はエラーをスローしますが、x <- y <- 5
はスローしないのはなぜですか?」という質問に対する答えです。 「それはパーサに含まれる魔法のせいです」 Rの構文には 多くの曖昧な場合 が含まれていますが、これらは何らかの方法で解決する必要があります。パーサーは、=
と<-
のどちらが使用されたかに応じて、式のビットを異なる順序で解決することを選択します。
何が起こっているのか理解するためには、代入が暗黙のうちに代入された値を返すことを知る必要があります。 print(x <- 2 + 3)
のように、明示的に印刷することでより明確にわかります。
次に、代入にプレフィックス表記を使用するとより明確になります。そう
x <- 5
`<-`(x, 5) #same thing
y = 5
`=`(y, 5) #also the same thing
パーサーはx <- y <- 5
を次のように解釈します。
`<-`(x, `<-`(y, 5))
x <- y = 5
は、
`<-`(x, `=`(y, 5))
しかし実際には
`=`(`<-`(x, y), 5)
これは、 =
ヘルプページに示されているように、<-
が?Syntax
より優先順位が低いためです。
GoogleのRスタイルガイドでは、代入に "="を禁止することで問題を単純化しています。悪い選択ではありません。
https://google.github.io/styleguide/Rguide.xml
Rマニュアルは、5つの代入演算子すべてに関する詳細な説明に入ります。
http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html
代入演算子は右から左に「グループ化」するので、x = y = 5
はx = (y = 5)
と同じです。意味:y
に5を代入し、5を残します。そしてその5をx
に代入します。
これは(x = y) = 5
と同じではありません。意味:y
の値をそのままに、x
にy
の値を代入します。それから、5を代入してください。
さまざまな種類の代入演算子を混在させると、<-
は=
よりも強くバインドされます。そのため、x = y <- 5
はx = (y <- 5)
として解釈されますが、これは意味があります。
残念ながら、x <- y = 5
は(x <- y) = 5
として解釈されますが、これは機能しません。
優先順位(バインド)とグループ化の規則については、?Syntax
と?assignOps
を参照してください。
John Chambersによると、演算子=
は「トップレベル」でのみ許可されています。これはif
のような制御構造では許可されていないことを意味し、次のプログラミングエラーは違法になります。
> if(x = 0) 1 else x
Error: syntax error
彼が書いているように、 "制御式の中で新しい代入形式[=]を許可しないことは、他のS代入よりも等号演算子で起こりそうなプログラミングエラー(上の例のような)を避けます"。
「括弧や余分な括弧によって周囲の論理構造から分離されている」場合は、これを実行してif ((x = 0)) 1 else x
が機能するようにすることができます。
Rの代入演算子
=
と<-
の違いは何ですか?
あなたの例が示すように、=
と<-
はわずかに異なる演算子優先順位を持っています(これは、それらが同じ式の中で混在するときに評価の順序を決定します)。実際、Rの ?Syntax
は、最高から最低の順に、次の演算子優先順位表を与えます。
… ‘-> ->>’ rightwards assignment ‘<- <<-’ assignment (right to left) ‘=’ assignment (right to left) …
しかし、これだけの違いはありますか?
代入演算子:について尋ねていたので、それが唯一の違いです。しかし、そうでないと信じることは許されるでしょう。 ?assignOps
のR文書でさえも、もっと違いがあると主張しています。
演算子
<-
は任意の場所で使用できますが、演算子=
はトップレベル(たとえば、Promptコマンドで入力された完全な式の中)、または式の中括弧付きリストの中の部分式の1つとしてのみ使用できます。
細かい点には注意しないでください。Rのドキュメントは(微妙に)間違っています [ 1 ]。これは簡単に示すことができます。(a)トップレベルでも(b)式の中括弧で囲まれた部分式(つまり=
)でもない{…; …}
演算子の反例を見つける必要があります。 - 難しい話は抜きにして:
x
# Error: object 'x' not found
sum((x = 1), 2)
# [1] 3
x
# [1] 1
明らかに、コンテキスト(a)と(b)の外側で=
を使って代入を実行しました。それでは、なぜコアR言語機能の文書化が何十年もの間間違っていたのはなぜでしょうか。
これは、Rの構文では、シンボル=
が2つの異なる意味を持ち、それらが日常的に混同されているからです。
=
演算子とは異なり、実行時にアクションを実行するのではなく、単に式の解析方法を変更するだけです。どれどれ。
一般形式のコードでは…
‹function_name›(‹argname›=‹value›, …)
‹function_name›(‹args›, ‹argname›=‹value›, …)
…=
は、名前付き引数の受け渡しを定義するトークンです。これは、not代入演算子です。さらに、いくつかの構文上の文脈では、=
は完全に禁止です。
if (‹var›=‹value›) …
while (‹var›=‹value›) …
for (‹var›=‹value› in ‹value2›) …
for (‹var1› in ‹var2›=‹value›) …
これらのいずれもが「予想外の '=' ‹bla›」というエラーを発生させます。
それ以外の文脈では、=
は代入演算子呼び出しを表します。特に、部分式を括弧で囲むだけで、上記の(a)が有効になり、(b)assignmentが有効になります。例えば、以下は代入を実行します。
median((x = 1 : 10))
だけでなく:
if (! (nf = length(from))) return()
今、あなたはそのようなコードが残虐であると反対するかもしれません(そしてあなたは正しいかもしれません)。しかし、私はこのコードをbase::file.copy
関数から取りました(<-
を=
に置き換える) - それは、コアRコードベースの大部分で普及しているパターンです。
Rのドキュメントがおそらく基づいているJohn Chambersによる オリジナルの説明 は、実際にこれを正しく説明しています。
[
=
の割り当ては]文法の中で2つの場所だけで許されています:トップレベルで(完全なプログラムまたはユーザタイプの式として);そして、中括弧または余分な括弧の対によって、周囲の論理構造から分離されている場合。
告白:私は先に嘘をついた。はです=
演算子と<-
演算子のもう1つの違いは、これらは異なる関数を呼び出すということです。デフォルトではこれらの関数は同じことをしますが、どちらかを別々にオーバーライドして動作を変更することができます。対照的に、<-
と->
(左から右への代入)は、構文的には異なりますが、常にsame関数を呼び出します。一方を上書きすると、もう一方も上書きされます。これを知っていることはめったに実用的ではありませんが 、canは楽しいことができます 。
演算子<-
と=
は、それらが評価される環境に割り当てられます。演算子<-
はどこでも使用できます、一方、演算子=
はトップレベルでのみ許可されます(たとえば、プロンプトで入力された完全な式の中、または式の中括弧付きリストの中の部分式の1つとして。
これにより、これら2つの演算子の違いを理解することができます。
df <- data.frame(
a = rnorm(10),
b <- rnorm(10)
)
最初の要素のRは値と固有の名前を割り当てていますが、2番目の要素の名前は少し奇妙に見えます。
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バージョン3.3.2(2016-10-31)。 macOS Sierra 10.12.1