在R中插入bquote的拼接

11

假设我用 R 语言的反引号运算符 bquote 来构建一个表达式,并且我想在特定位置上“插入”一个列表(也就是说,去掉列表的外层括号)。

例如,我有一个表达式“5+4”,我想在它前面添加“6-”,但不使用字符串操作(也就是说,完全在符号结构上操作)。

所以:

>   b = quote(5+4)
>   b
5 + 4
>   c = bquote(6-.(b))
>   c
6 - (5 + 4)
>   eval(c)
[1] -3

我希望它返回"6-5+4"的计算结果,即5。

在Common Lisp中,反引号"`"操作符配有一个插入运算符", @",可以完全做到这一点:

CL-USER> 
(setf b `(5 + 4))
(5 + 4)
CL-USER> 
(setf c `(6 - ,@b))
(6 - 5 + 4)
CL-USER> 
(setf c-non-spliced `(6 - ,b))
(6 - (5 + 4))
CL-USER> 

我尝试在R中使用.@(b),但没有成功。还有其他的想法吗?重申一遍,我不想使用字符串操作。


我认为在基本层面上,这都是“字符串操作”。 - IRTFM
3个回答

6

这是个很有趣的问题。经过一番尝试,我只能为你提供以下针对特定示例的解决方案。

> b <- quote(5 + 4)
> b[[2]] <-  bquote(6 - .(b[[2]]))
> b
6 - 5 + 4
> eval(b)
[1] 5

不幸的是,这可能很难概括,因为您必须考虑评估顺序等因素。


3

你需要意识到,R表达式并不是按照它们的打印方法所呈现的中缀顺序存储的:

> b = quote(5+4)
>  b[[1]]
`+`
> b = quote(5+4)
>  b[[2]]
[1] 5
> b = quote(5+4)
>  b[[3]]
[1] 4

虽然语言对象的打印方法可能会让你认为 6 - 5 + 4 的第二个参数是 6-5,但实际上这并不正确。在 Python 中,加法运算符比减法运算符具有更高的优先级。

> b2 <- bquote(6 - 5 + 4)
> b2[[1]]
`+`
> b2[[2]]
6 - 5

...这也只是一种幻觉。它实际上具有一个列表结构。(我原以为这对Lisp用户来说是理所当然的。)

> b2[[3]]
[1] 4
> b2[[2]][[1]]
`-`
> b2[[2]][[2]]
[1] 6
> b2[[2]][[3]]
[1] 5

2
我知道它在底层是一个AST,但这并不能直接解决问题。 - Clayton Stanley
我同意这并不能解决问题,但我认为明确定义问题的适当维度将非常有帮助。我不太相信这是真正的问题,所以我更希望看到“用例”是什么。 - IRTFM
这绝对暗示了一种实现 .@. 的方法。我有点希望已经有一个代码遍历库可以做到这一点,希望有人知道。 - Clayton Stanley
不确定如何找到或甚至是什么是“代码漫步库”,但您是否查看了bquote的代码? - IRTFM
@ClaytonStanley,codetools包中有一个walkCode函数...我不知道它是否有帮助。 - GSee
1
@IShouldBuyABoat 如果bquote具备splice功能,这里有一个可能的用例刚刚在SO上发布:https://dev59.com/9H3aa4cB1Zd3GeqPcWBW#22336062 - Clayton Stanley

2
在即将发布的 R 4.0.0 版本中,bquote 中有一个新功能,名为 splice expression。详细信息请参见相关新闻条目:https://cran.r-project.org/doc/manuals/r-devel/NEWS.html
backquote 函数 bquote() 现在有一个新参数 splice,用于将计算出的值列表拼接到表达式中,类似于 LISP 的 backquote 中的 ",@"。下面是手册中的示例:https://stat.ethz.ch/R-manual/R-devel/library/base/html/bquote.html
exprs <- expression(x <- 1, y <- 2, x + y)
bquote(function() {..(exprs)}, splice = TRUE)
#function() {
#    x <- 1
#    y <- 2
#    x + y
#}

很遗憾,它并不能解决您的使用情况:

e = quote(5 + 4)
bquote(6 - ..(e), splice=TRUE)
#6 - (5 + 4)

放弃括号不是很容易实现,因为需要旋转AST。这是由于R实现AST的方式造成的。请参照其他答案来找到可行的解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接