我对最基本的东西,评价,如何在R中起作用感兴趣。
我作为一名生物学家来到R,但对与代码相关的一切感兴趣,它仍然有点神秘。
我想我理解得很好:
但从技术上讲,当我们在一个(或更多)代码行之后按Enter键时,当我们评估R中的某些东西时幕后会发生什么?
我在核心团队的R language definition中找到了这个:
当用户在提示符下键入命令时(或者从文件中读取表达式时),首先发生的事情是,解析器将命令转换为内部表示。求值程序执行已解析的R表达式并返回表达式的值。所有表达式都有一个值。这是该语言的核心。
但这对我来说是深奥的(特别是粗体部分)而且这一小节并没有帮助我解开这个问题。
我是否必须打开一本关于信息学的基础书才能理解这一点,还是有另一种方法可以从技术上理解我每天8小时都在做什么?
答案 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 + +
^
这不是一个完整的故事,但也许它会帮助你理解。