2017-07-12 4 views
1

私はrlangパッケージを使って、右辺式(代入する値)と左辺式(代入先)を指定して、代入を行う式を作成しようとしています。たとえば、のは、私が表現a <- 5を構築し、評価したいとしましょう:rlangを使用して代入式を作成することはできますか?

> library(rlang) 
> a <- "Not 5" 
> lhs <- quo(a) 
> rhs <- quo(5) 
> eval_tidy(quo((!!lhs) <- (!!rhs))) # Error 
Error in (~a) <- (~5) : could not find function "(<-" 
> eval_tidy(quo(`<-`(!!lhs, !!rhs))) # Error 
Error in ~a <- ~5 : could not find function "~<-" 
> eval_tidy(quo(`<-`(!!f_rhs(lhs), !!rhs))) # No error, but no effect 
[1] 5 
> stopifnot(a == 5) 
Error: a == 5 is not TRUE 
> print(a) 
[1] "Not 5" 

あなたが見ることができるように、この割り当てを構築し、評価する上記の方法のいずれも所望の効果を持っていません。これを正しく行う方法はありますか?

編集:それは変数だけではなく、オブジェクトの要素のために働くためassignを使用する代わりに<-することは、良い解決策ではありません。

> a <- list(ShouldBeFive="Not 5") 
> lhs <- quo(a$ShouldBeFive) 

編集2:たとえば、それは動作しません私が達成しようとしているものを示しているproof of conceptを書かれています。任意の左辺を可能にするassign_general関数を定義します。 assign_general(a[[1]], 5)a[[1]] <- 5に相当します。しかし、私の実装はちょっとハッキリしているようですが、私は見逃しているかもしれないコーナーケースを知りませんし、もっと直接的な方法があればまだ分かりません。よりよい解決策です。

+0

'assign'だけ使用できますか? – Dason

+0

'assign'は任意の左辺では動作しません。 'lhs < - quo(a [[1]])'ならば? –

+0

rlangを使用している理由を尋ねることはできますか? – Dason

答えて

0

メタプログラミングの利点は、式を文字列として使用し、文字列として宣言できるL値への代入を実行できることです。割り当て関数は、場合によってはメタプログラミングで再利用可能です。

rhs <- "1 > 0" 
assign("lhs", eval(eval_tidy(parse(text=rhs)))) 
lhs 
[1] TRUE 

以上、lhsとrhsの両方が文字列として渡され、式がL値に割り当てられていることがわかります。暗黒魔法の少しと私はあなたが後にあるものを達成することができたいくつかの幸運で

+0

コメントで述べたように、 'assign'は十分に一般的ではありません。 '< - 'とは異なり、リスト内の要素やオブジェクトの他の部分に割り当てることはできません。環境内の変数名にのみ割り当てることができます。 –

0

library(rlang) 

expr<-quote(x<-1) # just some sample assignment operator to modify 
a <- list(ShouldBeFive="Not 5") 
lhs <- quo(a[[1]]) 
rhs <- quo(5) 

expr[[2]] <-UQE(eval(lhs)) 
expr[[3]] <-UQE(eval(rhs)) 
expr 
>a[[1]] <- 5 

eval(expr) 
a$ShouldBeFive 
>5 

ここrlangに依存しない、できればクリーンな代替です:

b <- list(ShouldBeSix="Not 6") 
lhs <- quote(b[[1]]) 
rhs <- quote(6) 

eval(substitute(x <- value,list(x = lhs, value = eval(rhs)))) 
b$ShouldBeSix 
1

1)rlang :: langrlang::langは次のように使用できます。

library(rlang) 

# inputs 
a <- "Not 5" 
lhs <- quote(a) 
rhs <- 5 

L <- lang("<-", lhs, rhs) 
eval(L) 
a 
## [1] 5 

2)又はlangの代わりにrlang使用callなしを呼び出す:

# inputs 
a <- "Not 5" 
lhs <- quote(a) 
rhs <- 5 
cc <- call("<-", lhs, rhs) 

eval(cc) 
a 
## [1] 5 

2A)上記のどちらもlhsは、適切な発現である場合に動作します。

# inputs 
BOD2 <- BOD 
lhs <- quote(BOD2$xyz) 
rhs <- 5 

cc <- call("<-", lhs, rhs) 
eval(cc) 
names(BOD2) 
## [1] "Time" "demand" "xyz" 

図2b)

assign_general <- function(lhs, rhs, envir = parent.frame()) { 
     cc <- call("<-", substitute(lhs), substitute(rhs)) 
     eval(cc, envir = envir) 
} 

# test 
a <- 1:5 
assign_general(a[3], 5) 
a 
## [1] 1 2 5 4 5 

assign_general callにいくつかの選択肢の文のようになります。:

cc <- substitute(call("<-", lhs, rhs)) 

または

例えば、組み込みのデータフレーム BODを使用してもちろん3210

2C)この十分であろう:(2B)langcallを置き換えることによって得ることができ、substituteとでassign_generalの assign_general rlang実装の

assign_general2 <- `<-` 

a <- 1:5 
assign_general2(a[3], 5) 
## [1] 1 2 5 4 5 

3)rlangバージョンenexpr

library(rlang) 
assign_general3 <- function(lhs, rhs, envir = parent.frame()) { 
     L <- lang("<-", enexpr(lhs), enexpr(rhs)) 
     eval(L, envir = envir) 
} 

# test 
a <- 1:5 
assign_general3(a[3], 5) 
a 
## [1] 1 2 5 4 5 

4)弦もう1つの可能性は、引数を文字列に分解することです:

assign_general4 <- function(lhs, rhs, envir = parent.frame()) { 
    s <- paste(deparse(substitute(lhs)), "<-", deparse(substitute(rhs))) 
    p <- parse(text = s) 
    eval(p, envir = envir) 
} 

# test 
a <- 1:5 
assign_general4(a[3], 5) 
a 
## [1] 1 2 5 4 5 
関連する問題