懒惰评估:为啥我不能使用 plot(..., xlim = c(0,1), ylim = xlim)?

Posted

技术标签:

【中文标题】懒惰评估:为啥我不能使用 plot(..., xlim = c(0,1), ylim = xlim)?【英文标题】:Lazy Evaluation: Why can't I use plot(..., xlim = c(0,1), ylim = xlim)?懒惰评估:为什么我不能使用 plot(..., xlim = c(0,1), ylim = xlim)? 【发布时间】:2014-07-12 03:59:09 【问题描述】:

R 最大的特点之一是惰性求值。这导致了一种经常遇到的风格,即可以使用一个参数作为另一个参数的值。例如,在 Hadley 关于Advanced R 的伟大著作中,您会看到this example:

g <- function(a = 1, b = a * 2) 
  c(a, b)

g()
#> [1] 1 2
g(10)
#> [1] 10 20

现在,我想对 xlimylim 的绘图做同样的事情,但是它不起作用:

> plot(1, 1, ylim = c(0,1), xlim = ylim)
Error in plot.default(1, 1, ylim = c(0, 1), xlim = ylim) : 
  object 'ylim' not found
> plot(1, 1, xlim = c(0,1), ylim = xlim)
Error in plot.default(1, 1, xlim = c(0, 1), ylim = xlim) : 
  object 'xlim' not found
有人知道为什么吗? 还有办法实现这一目标吗?

【问题讨论】:

我认为这很容易用adv-r.had.co.nz/Environments.html 中的更新定义来解释:默认参数评估函数的执行环境,提供的参数评估函数的调用环境。 【参考方案1】:

Quoting from the good manual:

4.3.3 参数评估

关于评估的最重要的事情之一 函数的参数是提供的参数和默认值 论据被区别对待。为 a 提供的参数 函数在调用的评估框架中进行评估 功能。函数的默认参数在 函数的评估框架。

要了解这在实践中意味着什么,请创建一个函数,其中一个参数的默认值是另一个参数值的函数:

f <- function(x=4, y=x^2) 
    y

当使用y默认值 调用时,R 会在函数调用的评估框架中评估y,即在与函数的整个主体相同的环境中得到评估——x 有更好的地方(当然确实存在):

f() 
# [1] 16

当使用 提供的值 y 调用时,R 会查看调用函数的评估框架(此处为全局环境),找不到 x,并让您知道它的错误信息:

f(y=x^2)
# Error in f(y = x^2) : object 'x' not found

【讨论】:

最后一行很有趣。因此,即使您已将默认 x 值设置为 4,R 也不会在评估框架中找到它?显然“不”,但有点难以理解为什么。 @RichardScriven -- 是的,这就是我使用这个例子的原因 :-) 直到你真正完全掌握它的那一刻,你才会感到舒服! (对我来说,那一刻是在第一次阅读那篇文章几年后出现的;希望这将有助于加快其他人的进程!) ...这可能不会太远,因为您现在让我感到好奇。 :) 我也不知道默认函数参数会进入全局环境。我认为他们留在了函数环境中,而函数进入了全局环境。我有读书要做! 有没有办法强制在函数调用的框架内评估提供的参数?例如,与常见的嫌疑人之一:evalsubstitute、... 不,没有办法。不过,您可以设置一个函数来对提供的参数进行非标准评估。例如,想想将公式作为参数的函数,或者看看 curve 函数对其初始 expr 参数的作用。【参考方案2】:

这里有一个范围界定问题。在语句plot(1, 1, ylim = c(0,1), xlim = ylim) 中,名称ylim 仅作为参数名称可用,一般调用者无法使用。

对于要在赋值右侧使用的变量,它必须在调用范围内可用。

您的第一个示例有效的原因是因为您将 默认参数 写入函数定义中,而 确实 可以访问所有参数。

一种可能的解决方法是,将 plot 函数包装在一个新函数中有这种行为。

myplot <- function(x, y, ylim, xlim = ylim,...) 
  plot(x,y, ylim = ylim, xlim = xlim,...)


myplot(1,1, ylim=c(0,1))

【讨论】:

但是为什么它在上面的例子中有效(对不起,第一个例子是错误的)? @Henrik,我刚刚更新了。第二种情况是一个函数call,它的作用域是调用者的上下文。第一个场景是一个函数定义,它的作用域是被调用者的上下文。 @Henrik,我还更新了一个有点弱的解决方法。

以上是关于懒惰评估:为啥我不能使用 plot(..., xlim = c(0,1), ylim = xlim)?的主要内容,如果未能解决你的问题,请参考以下文章

为啥除了 Pixel XL 设备在 android studio 模拟器中所有 ADV 设备都不能工作?

为啥我不能将 x 和 y 标签设置为 pd.plot() 的参数,而我可以轻松设置类似的东西,例如标题?

为啥我不能使用正则表达式来评估 if...else 语句 [重复]

Haskell 不会懒惰地评估交错

无限列表中的懒惰评估

Python 会懒惰地评估 if 的条件吗? [复制]