何时决定使用括号调用R函数,何时不使用括号

4

我正在学习R语言。

为什么有时候在R中调用函数时要用括号,例如 myfunction(),而有时候不用括号,例如 myfunction

我应该如何知道何时使用括号以及何时不用?

我发现tidyverse中许多函数调用都没有括号。


1
@AugtPelle... Java...是用来创造R的语言?我之前没有听说过这个,且难以置信:S最初是在1976年左右编写的,而开源版本的R则是在1992年开始并在1995年发布的(参考链接:https://en.wikipedia.org/wiki/R_(programming_language)和https://blog.revolutionanalytics.com/2020/07/the-history-of-r-updated-for-2020.html);而Java是在1995年发布的(https://en.wikipedia.org/wiki/Java_(programming_language))。S受到C、APL、PPL和Fortran的影响;R受到Common Lisp、Scheme和(当然)S的影响。 - r2evans
4
你能否提供一个你见过的这样的例子?我怀疑是因为 magrittr 管道。在这种情况下,x %>% sumsum(x)x %>% sum()相同。请注意,根据tidyverse风格指南,不写括号是不好的做法 - Donald Seinen
1
@AugtPelle,那简直是完全错误的。(a)R不是使用Java创建的,而且比它更早。(b)与R不同,Java 强类型的。(c)这与强类型无关。(d)这是完全合乎逻辑的,并受到一致的规则支配。 - Konrad Rudolph
@AJAY 请提供更多细节。目前为止,无法回答你的问题,因为它似乎基于错误的前提(Donald的评论除外)。 - Konrad Rudolph
1
抱歉!我的意思是C语言,不是Java!!!我很抱歉。 - AugtPelle
显示剩余5条评论
2个回答

12

在 R 语言中,您可以将函数视为一个对象。该对象有两个组成部分:函数接受的参数(称为 形式参数),以及花括号内的实际代码,即函数 主体

例如,让我们定义一个名为 f 的简单函数:

f <- function(x) { x + 1 }

如果我们在控制台中只输入没有括号的f,我们就可以看到这个新对象f的形式和内容。
f
#> function(x) { x + 1 }
#> <bytecode: 0x000001f8dc3e3f50>

我们可以通过执行以下操作分别查看其形式:

formals(f)
#> $x

通过以下方式处理其主体:

body(f)
#> {
#>     x + 1
#> }

因此,函数实际上只是一个对象。但通常我们希望使用这个函数来为我们进行一些计算。我们通过调用函数来使用它。这意味着我们将一些值给出到形式参数中,并在函数主体内部使用这些值进行计算。

当我们调用一个函数时,通常是在函数名称后面的括号中放置变量:

f(1)
#> [1] 2

但这不是调用函数的唯一方式。例如,我们可以使用do.call将函数名和要传递给它的参数传递给R:

do.call(f, list(x = 1))
#> [1] 2

我们甚至可以将调用的函数名和参数作为一个列表构建,然后直接要求R进行评估:
eval(as.call(list(f, x = 1)))
#> [1] 2

但最常见的方式是在函数名称后面加上参数括号。R解析器将其识别为“使用这些参数调用该函数”。请注意,即使没有名称,该函数也可以正常工作:

(function(x){ x + 1 })(1)
#> [1] 2

有时我们会看到函数没有括号的情况,这是因为函数本身也是对象,可以被传递给其他函数。例如,假设我们有以下函数:
call_func_with_data <- function(func, data) {
  do.call(func, list(data))
}

我可以传入任何函数并尝试使用我传递的数据调用它:
z <- 1:10

call_func_with_data(mean, z)
#> [1] 5.5
call_func_with_data(min, z)
#> [1] 1
call_func_with_data(max, z)
#> [1] 10
call_func_with_data(f, z)
#>  [1]  2  3  4  5  6  7  8  9 10 11

请注意,我使用了所有这些函数而没有使用括号。这本质上是 tidyverse 和 apply 类型函数内部发生的情况,在这些函数中,您会看到函数名称后面没有括号。当您使用以下语法时也会发生这种情况:
1 %>% f
#> [1] 2

这些只是调用函数的不同方式。

此代码片段由reprex包(v2.0.1)在2022-01-29创建。


3

实际上只有两种可能性:

  1. Call the function by putting parentheses after it, e.g. sqrt(4)

  2. Pass the function itself to another function which in turn invokes it. In this case we are not calling the function but passing it on as an argument to another function. e.g.

     sapply(1:4, sqrt) # pass sqrt to sapply which invokes it repeatedly
     do.call(sqrt, list(4))  # pass sqrt to do.call which in turn invokes it
    

中缀表达式

还有一种中缀函数,如+(它们放置在其参数之间)和一元函数,它们放置在其参数之前,但这些只是表面上的不同,在底层实际上是相同的。例如,下面两个表达式是相同的。

   1+2
   `+`(1, 2)

这些是相同的

!TRUE
`!`(TRUE)

管道

还有管道,但这只是一种操纵语法的方式,从概念上讲,两者是相同的。

 sqrt(4)
 4 |> sqrt()

magrittr包也有管道,所以这些概念上都是相同的。这里它将sqrtsqrt()传递给%>% 中缀函数,然后将其解释为下面第一个sqrt行。

library(magrittr)

sqrt(4)
4 %>% sqrt
4 %>% sqrt()

谢谢,解释得非常好! - AJAY

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