Rによるラベル付きループ


この記事の内容は誤っているかもしれません。

そもそも、Rでforを使うのはダメ、というのは嘘。多分ベクトル化に関して誤解があります。

applyはただのラッパで、実際はforをつかうよ、の理由を書こうと思ったんだけど、@a_bickyさんがapplyの解説記事を書いてくれたので、そっちを見て下さい。とにかく、Rでもforは使うんです。

[R の apply 徹底解説](http://d.hatena.ne.jp/a_bicky/20120425/1335312593)

## Rでは多重ループがよく出てくる。

多次元配列とか使うと出てきます。当たり前です。まあなんでもいいんですが、多重ループ途中で条件によって全ループ脱出したい、という場合があるかもしれません。

例えばC系だと、gotoを使うか、フラグを使うかします。以下の例は、[trinoの走り書き](http://d.hatena.ne.jp/n-trino/20090604/p1)っていうブログからお借りしました。ありがとう。

```c
for( int z = 0; z < iSizeZ; ++z ){
	for( int y = 0; y < iSizeY; ++y ){
		for( int x = 0; x < iSizeX; ++x ){
			if( ... ){
				goto LABEL;
			}
		}
	}
}
LABEL:
```

とか

```c
bool bEnd = false;
for( int z = 0; z < iSizeZ; ++z ){
	for( int y = 0; y < iSizeY; ++y ){
		for( int x = 0; x < iSizeX; ++x ){
			if( ... ){
				bEnd = true;
			}
			if( bEnd ){ break; }
		}
		if( bEnd ){ break; }
	}
	if( bEnd ){ break; }
}
```

とか。あと、関数を使うのもあり。

```c
void Loop()
{
	for( int z = 0; z < iSizeZ; ++z ){
		for( int y = 0; y < iSizeY; ++y ){
			for( int x = 0; x < iSizeX; ++x ){
				if( ... ){
					return;
				}
			}
		}
	}
}
```

Rではフラグを使うか、関数を作るか、tryでエラー起こすか、というのが手ですが、

1. フラグ面倒。バグ入りがち。
2. 関数はあり。Rはどこでも関数が定義できるので、なおアリ。でもスコープの問題があって、関数の中の副作用（代入とかね）はデフォで関数内しか効かない。
3. エラーtryは、予定外のエラーも拾ってパスしちゃうから、なし。一応`stop(e)`で例外投げて、分岐すればOKかもだけど、多重ループ脱出のために条件分岐してエラー投げて、受け取った側でエラーの中身見て条件分岐、とか、ないわ。

## Rによる多重ループの脱出

[前回の記事](http://qiita.com/items/e61c2f276a157edd7fe8)で書いたとおり、シグナリング機構を使うと多重ループが実装できる。

やってることは以下の通り、

1. 関数(`._.()`)に多重ループ式を渡す。
2. シグナル埋め込む(`.Internal(.addRestart(…))`)。
3. 式を評価する関数を評価する。
3. 多重ループ式中では、ある条件でシグナルを生成する(`.V.`)。
4. 式を評価する関数の評価が停止して、呼び出し環境に戻る。
5. 関数を抜ける。

という感じです。プロミスとして渡された式を評価してるので、式の環境は呼び出し元の環境になっています。つまりグローバルから呼び出したら、グローバルの変数の書き換えも可能ということ。要するに、スコープ気にしないで普通の式みたいに使える、ということ。

## ラベル付きループ

Java（など）にはラベル付きループというものがあって、多重ループの中のどのループまで抜けるか指定できる。これは便利。[こういうの](http://www1.bbiq.jp/takeharu/java38.html)ね。

で、これをRで（あとmatlabでも）使えるといいなあ、と思っていたんだけど、多重ループ脱出のことを考えたら出来るような気がして、書いてみたらできた。CRANから使えます。

[CRAN - Package labeledLoop](http://cran.r-project.org/web/packages/labeledLoop/index.html)

これフル脱出。

```R
> library(labeledLoop)
> A %._.% for (i in 1:3) {
+ 	B %._.% for (j in 4:6) {
+ 		C %._.% for (k in 7:9) {
+ 			if (i == 2 && j == 5 && k == 8) {
+ 				print(c(i, j, k))
+ 				._.(A)
+ 			}
+ 		}
+ 	}
+ }
[1] 2 5 8
```

真ん中を抜ける。

```R
> A %._.% for (i in 1:3) {
+ 	B %._.% for (j in 4:6) {
+ 		C %._.% for (k in 7:9) {
+ 			if (k == 8) {
+ 				print(c(i, j, k))
+ 				._.(B)
+ 			}
+ 		}
+ 	}
+ }
[1] 1 4 8
[1] 2 4 8
[1] 3 4 8
```

という感じです。

## 実装についてのメモ

ソースコードは[github](https://github.com/kohske/labeledLoop)においてあります。

パッケージとは言っても、中身は`%._.%`という演算子と`._.`という関数があるだけ。あわせて10行くらいです。

```R
`%._.%` <- function(label, statement) {
  label <- substitute(label)
  if (!is.character(label)) label <- deparse(substitute(label))
  arg <- list(as.name("statement"), label)
  names(arg) <- c("expr", label)
  do.call("withRestarts", arg)
  invisible()
}

`._.` <- function(label = ".") {
  label <- substitute(label)
  if (!is.character(label)) label <- deparse(substitute(label))
  invokeRestart(label)
}
```

`%._.%`は左辺にラベル、右辺に式をとる演算子です。ラベルを受けフラグとしてリスタートを仕込んでます(`withRestarts`)。それだけ。

`._.`はラベルを引数にする関数。リスタートを発行します。それだけ。

`withRestarts`は任意の仮引数の「名前」で、`invokeRestart`のフラグを判定するんだけど、一番面倒なのが、動的に渡されるラベルを使って引数を作るところ。まあ`eval(parse(text)))`しちゃえばいいんですが・・・。

## まとめ

というわけで、@a_bickyさんのいうように、Rではfor使ったほうがいい場面が結構あります。そんな時に使えるライブラリかもしれません。