R评估过程中会发生什么?

时间:2016-04-06 12:25:28

标签: r evaluation

我对最基本的东西,评价,如何在R中起作用感兴趣。

我作为一名生物学家来到R,但对与代码相关的一切感兴趣,它仍然有点神秘。

我想我理解得很好:

但从技术上讲,当我们在一个(或更多)代码行之后按Enter键时,当我们评估R中的某些东西时幕后会发生什么?

我在核心团队的R language definition中找到了这个:

  

当用户在提示符下键入命令时(或者从文件中读取表达式时),首先发生的事情是,解析器将命令转换为内部表示。求值程序执行已解析的R表达式并返回表达式的值。所有表达式都有一个值。这是该语言的核心。

但这对我来说是深奥的(特别是粗体部分)而且这一小节并没有帮助我解开这个问题。

我是否必须打开一本关于信息学的基础书才能理解这一点,还是有另一种方法可以从技术上理解我每天8小时都在做什么?

1 个答案:

答案 0 :(得分:4)

这将是一个不完整的答案,但似乎你的问题是关于内部代表性的本质。"从本质上讲,R的解析器采用任意R代码,删除不相关的东西(如多余的空格)并创建一组嵌套的表达式来进行评估。我们可以使用pryr::call_tree()查看发生了什么。

采用仅使用数学运算符的简单表达式:

> 1 + 2 - 3 * 4 / 5
[1] 0.6

在该系列操作中,会出现一个尊重R优先规则的输出。但究竟发生了什么?首先,解析器将输入的任何内容转换为"表达式":

> parse(text = "1 + 2 - 3 * 4 / 5")
expression(1 + 2 - 3 * 4 / 5)

这个表达掩盖了更深层次的复杂性:

> library("pryr")
> call_tree(parse(text = "1 + 2 - 3 * 4 / 5"))
\- ()
  \- `-
  \- ()
    \- `+
    \-  1
    \-  2
  \- ()
    \- `/
    \- ()
      \- `*
      \-  3
      \-  4
    \-  5

此表达式是对四个函数的顺序评估,首先是"*"(),然后是"/"(),然后是"+"(),然后是"-"()。因此,实际上可以将其重写为深层嵌套的表达式:

> "-"("+"(1,2), "/"("*"(3,4), 5))
[1] 0.6
> call_tree(parse(text = '"-"("+"(1,2), "/"("*"(3,4), 5))'))
\- ()
  \- `-
  \- ()
    \- `+
    \-  1
    \-  2
  \- ()
    \- `/
    \- ()
      \- `*
      \-  3
      \-  4
    \-  5

多行表达式也被解析为单个表达式:

> parse(text = "1; 2; 3")
expression(1, 2, 3)
> parse(text = "1\n2\n3")
expression(1, 2, 3)
> call_tree(parse(text = "1; 2; 3"))
\-  1

\-  2

\-  3

然后评估这些调用树。

因此,当R的read-eval-print循环执行时,它会将解释器中输入的代码或源自文件的代码解析为此调用树结构,然后依次计算每个函数调用,然后打印结果,除非发生错误)。如果无法完全评估可解析的代码行,则会发生错误:

> call_tree(parse(text = "2 + 'A'"))
\- ()
  \- `+
  \-  2
  \-  "A"

当无法将一长串代码解析为调用树时,会发生解析失败:

> parse(text = "2 + +")
Error in parse(text = "2 + +") : <text>:2:0: unexpected end of input
1: 2 + +
   ^

这不是一个完整的故事,但也许它会帮助你理解。