LoginSignup
0
1

More than 5 years have passed since last update.

Rで局所的な変数束縛ごっこ

Last updated at Posted at 2017-01-01

はじめに

年末年始でヒマなので、Haskell ライクな局所的な変数束縛や関数に対してのみ有効な変数束縛を R で実現して遊ぼうというのをやってみました。

動機

何かカッコいいじゃないですか、こういうの。

velocity x1 x2 t1 t2 = dx / dt
  where
    dx = x2 - x1
    dt = t2 - t1

変数の順番考えずに定義だけ並べて宣言的に書けるのとか。スコープがきっちり限定されるのとか。

あとlambda.rパッケージを見て楽しそうだなと思ったのとか、ですね。

実装

https://github.com/ngr-t/r-bindedEval に置いてます。一丁前にパッケージにしてみたのはパッケージの作り方の勉強も兼ねてです。

使い方

Haskell の let 式の真似をした let 関数はこんな感じです。Haskell 連呼するのって Haskell ガチ勢に殴られそうで怖いですね。
適当に束縛したい変数とその定義を並べて、.in引数に最終的に評価したい表現を渡します。

z <- let(x = 1, y = 2, .in = x + y)
# x と y には let 関数の外からはアクセスできない

velocity_let <- function (x1, x2, t1, t2) let(
  dx = x2 - x1,
  dt = t2 - t1,
  .in = dx / dt)

velocity_let(80, 90, 0, 0.5)
# [1] 20

もしかすると

z <- let(x = 1, y = 2) %.in% (x + y)

みたいな構文の方がそれっぽいかもしれません。そのうちこっちで書いてみるかもです。

where構文の真似っこは以下です。パイプを使って書いていますがこちらは関数を第一引数にします。関数の定義の際に使ってください。

velocity_where <- (function (x1, x2, t1, t2) {
  dx / dt
}) %>%
where(
  dx = x2 - x1,
  dt = t2 - t1)

velocity_where(80, 90, 0, 0.5)
# [1] 20

関数定義を()で括るのはちょっとイケてないのですが、そこは R の演算子の結合順序の関係で、そうしないと関数ではなくて{}のでくくった部分がwhere()関数の引数になってしまいます。

let() および where() 関数両方についてですが、束縛される変数の定義にほかの束縛された変数を使えます。順番は適当でも大丈夫です。なので

let(x = y * 2, y = 1, z = x * y, .in = z)
# [1] 2

とかでも問題ありません。

以下のように相互参照してるのはダメです。

let(x = y, y = x, .in = x + y)
# Error

今回の実装ではこの辺りはigraph::topological.sort()で評価順序を決めているんですが、delayedAssign()を使えば、こちらで難しいことを考えなくても R のインタープリタが必要に際してよしなに評価してくれます(あらかた書いたところでこの関数の存在を知りました)。

関数を束縛しても良いんですよ。

fire <- (function (x, w, threshold)
    heaviside(weighted_sum - threshold)) %>%
  where(
    heaviside = function (x) ifelse(x > 0, 1, 0),
    weighted_sum = sum(x * w))

全体的にありがたみの薄い例しか挙げられませんでしたね。

パターンマッチング

無茶言わないでください。

所感

R はキモいDSLが書きやすいですね、良くも悪くも。環境操作とか構文パースとか評価順序いじったりとか、いろいろ出来ますほんと。

パッケージ作るのは思っていたほどには面倒ではありませんでした。devtools::build() が静的言語解析?をやってくれるのも助かりますね。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1