为什么R使用部分匹配?

25

我知道对于列表,使用基本运算符$[[]进行索引时会进行部分匹配。例如:

ll <- list(yy=1)
ll$y
[1] 1

但我仍然是R语言的新手,这对我来说很新奇:函数参数的部分匹配。

h <- function(xx=2)xx
h(x=2)
[1] 2

我希望了解这是如何运作的。背后的机制是什么?这会有任何副作用吗?我想了解如何测试是否给出了xx参数?
在Andrie评论之后进行编辑:
在内部,R使用pmatch算法来匹配参数,下面是一个示例,说明其工作原理:
 pmatch("me",   c("mean", "median", "mode")) # error multiple partial matches
[1] NA
> pmatch("mo",   c("mean", "median", "mode")) # mo match mode match here
[1] 3

但是为什么R具有这样的特性呢?部分唯一匹配背后的基本思想是什么?


5
阅读 http://cran.r-project.org/doc/manuals/R-lang.html#Argument-matching - Andrie
1
@Andrie 谢谢你提供的链接!即使它没有解释为什么 R 有这个特性,我也会接受它作为答案。看起来这是其他功能的副作用,因为拥有多个部分匹配是错误的。 - agstudy
4
这里是对“为什么”的猜测。R被设计成一种命令行统计语言,是分析数据的快速简便方式。部分匹配使得命令行分析更加容易(但编程更加棘手)。 - csgillespie
1
使用[[进行索引时,默认情况下不执行部分匹配,因为参数exact = TRUE - Helix123
1个回答

25
部分匹配存在的目的是为了节省您键入长参数名称的时间。但它带来的风险是,函数可能会在以后增加与您的部分匹配冲突的额外参数。这意味着它仅适用于交互式使用-如果您正在编写将长时间保留的代码(例如,放入软件包中),则应始终编写完整的参数名称。另一个问题是通过缩写参数名称,可能会使您的代码难以阅读。
两个常见的好用法是:
1. 使用seq(或seq.int)函数时,使用len代替length.out。 2. 使用ls函数时,使用all代替all.names
比较:
seq.int(0, 1, len = 11) 
seq.int(0, 1, length.out = 11)

ls(all = TRUE)
ls(all.names = TRUE)

在这两种情况下,使用缩短的参数名称读取代码几乎同样容易,而且这些函数已经存在很长时间,稳定性足够高,不太可能添加具有冲突名称的另一个参数。
为了节省输入,更好的解决方案是使用变量和参数名称的自动完成,而不是使用缩写名称。 R GUI和RStudio使用TAB键支持此功能,Architect使用CTRL+Space支持此功能。

以下是R语言定义中的一些相关部分:

3.4.1 通过向量索引

...假设表达式为x[i]。根据i的类型,存在以下可能性:

字符。在i中的字符串与x的名称属性匹配,并使用结果整数。对于[[$,如果精确匹配失败,则使用部分匹配,因此如果x不包含名为“aa”的组件且“aabb”是唯一具有前缀“aa”的名称,则x$aa将与x$aabb匹配。对于[[,可以通过默认为NAexact参数控制部分匹配,表示允许部分匹配,但在发生时应发出警告。将exact设置为TRUE可防止发生部分匹配,FALSE值允许它并且不发出任何警告。请注意,[始终需要精确匹配。字符串""被特殊处理:它表示“没有名称”,不匹配任何元素(甚至没有名称的元素)。请注意,在提取而非替换时才使用部分匹配。

[另请参见?Extract]

4.3.2 参数匹配

函数求值的第一步是将形式参数与实际或提供的参数进行匹配。这是通过三遍过程完成的:

  1. 标签的精确匹配。对于每个命名的提供的参数,都会在形式参数列表中搜索名称完全匹配的项。如果同一个形式参数匹配多个实际参数或者反之,则会出现错误。

  2. 标签的部分匹配。将剩余的命名提供的参数与剩余的形式参数进行部分匹配。如果提供的参数的名称与形式参数的前半部分完全匹配,则认为这两个参数匹配。有多个部分匹配是错误的。请注意,如果f <- function(fumble, fooey) fbody,则f(f = 1, fo = 2)是非法的,即使第二个实际参数只匹配了fooey。但是f(f = 1, fooey = 2)是合法的,因为第二个参数完全匹配,并且不再考虑进行部分匹配。如果形式参数包含...,则部分匹配仅应用于它之前的参数。

  3. 位置匹配


请注意,使用子集化 tibble时不支持列名的部分匹配,$[[返回NULL。对于$,会给出警告。

1
有时候在ls中我甚至使用a=T。如果你知道参数名称,有时候你可以这么做。 - Rich Scriven
8
对于这个设计决策,我觉得部分匹配参数名称的特性令人摸不着头脑,可能会导致调试困难。
  1. 如果要传递长参数名,请不要一开始就将它们命名为长名称?
  2. 制表符自动完成真是太棒了!
- John Smith
5年后的评论:就我所知,R的早期版本并没有进行制表符自动完成。而S语言(我认为这个功能是基于它的)几乎肯定也没有。 - Ben Bolker
3
6.5年过去了,这仍然会导致调试方面的困扰。 - gaut

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