2014年6月24日火曜日

Rの論理演算子 & と &&、 | と || の違い

【1つのもの】(「&」と「|」)

 ベクトルのそれぞれの要素を評価

> c(TRUE, TRUE, FALSE, FALSE) & c(TRUE, FALSE, TRUE, FALSE)

[1]  TRUE FALSE FALSE FALSE


【2つのもの】(「&&」と「||」)

 ベクトルの1つ目の要素のみ評価

> c(TRUE, TRUE, FALSE, FALSE) && c(TRUE, FALSE, TRUE, FALSE)

[1] TRUE

前者はRの演算子や関数ではおなじみの挙動ですよね。

この動きについては、ヘルプを見れば書いてあります。呼び出し方は以下↓

> ?"&"
starting httpd help server ... done

訳は私によるアバウトなもの。

& and && indicate logical AND and | and || indicate logical OR.

「&」と「&&」は論理積(AND)を、
「|」と「||」は論理和(OR)を表します。

The shorter form performs elementwise comparisons in much the same way as arithmetic operators.

短い方の形式は、他の算術演算子と同じように、要素ごとの比較を行う。

The longer form evaluates left to right examining only the first element of each vector.


長い方の形式は、左から右へと評価を行い、両者のベクトルの最初の要素のみを比較する。

Evaluation proceeds only until the result is determined.

評価は結果が確定するまでしか行われない。

The longer form is appropriate for programming control-flow and typically preferred in if clauses.

長い方の形式は、プログラムのフロー制御に向いており、if文などに適している。


以後はけっこう蛇足な感じですので、お暇な方だけ・・・

「左から右へと評価」のところですが、こう解釈しました。例えば、

TRUE || FALSE && TRUE

という順序で並んでいた場合、まず「TRUE || FALSE」の部分が評価され、この部分がTRUEだと判明した後に、後続の「 && TRUE」が評価され、全体としてTRUEになる、と。

ただ、疑問なのは、ANDとORだけで構成される論理式において、評価順によって結果が変わるような例が思いつかないんですよね。どの順で評価しても同じ結果になるような気がして、わざわざ「左から右」と評価順を明記する必要があるのだろうかと、ちょっと気になりました。

で、もしかしたら「評価は結果が確定するまでしか行われない」と関連しているんじゃないかと思ったんですね。

左から評価していくけど、結果が確定したら、そのあとは評価しないから、評価の順序は気にしておいて、という意味かなと。

で、試してみました。

f1 <- function(){
  print("in f1")
  return(TRUE)
}
 
f2 <- function(){
  print("in f2")
  return(FALSE)
}
 
if ( f1() || f2() ){
  print("in if clause")
}


if文の条件の評価で、まずf1が呼ばれます。結果はTRUEであり、条件文の後続は||なので、f2の結果を知る必要はないですよね。なので、f2は呼びませんよ、というのがヘルプの意図するところだと。
で、実行してみると、

> if ( f1() || f2() ){
+   print("in if clause")
+ }


[1] "in f1"
[1] "in if clause"


おお、成功です。f2は呼ばれないままif文の中に入っています。

たしか、perlなんかでもこういう仕様になっていて、この仕様を使ってうまい感じでコードが書けたりしたように記憶しています。

ただ、結果がこの仕様に依存するようなコードを書くのは、自分一人専用のちょっとしたスクリプトでない限りは避けた方がいいようにも思います。

ちなみに、短い形式の方を使うと、

> if ( f1() | f2() ){
+   print("in if clause")
+ }


[1] "in f1"
[1] "in f2"
[1] "in if clause"


のように、f1の結果にかかわらず、f2は呼ばれることになります。

やっぱり、この仕様を活用するのは、ちょっと危険な匂いがしますよねえ。




0 件のコメント:

コメントを投稿