为什么is.recursive函数对于一个函数返回TRUE

4
根据帮助文档,is.recursive(x)函数的说明为:“如果x有递归结构(类似于列表),则返回TRUE,否则返回FALSE”。我不明白当x是一个函数时为什么会返回TRUE。例如:
is.recursive(mean)
# [1] TRUE

但似乎函数在任何有意义的意义上都不能是递归的,特别是因为它们甚至不能被子集化:

mean[[1]]
# Error in mean[[1]] : object of type 'closure' is not subsettable

这是 R 源代码的疏忽吗?还是函数应该被视为递归的有效理由?


我认为,我仍在学习!错误发生是因为您尝试对表示函数(此处为 mean)的变量进行子集操作,并且您使用 [ 对其进行子集操作,就像在数据框或向量中所做的那样... 我进一步认为,您的意图不是要进行子集操作,而是要使用 $ 访问函数中的项目。这在正常的 R 中可能没有太多意义,但是它是可能的:请参见此处https://coolbutuseless.github.io/2019/02/12/object-of-type-closure-is-not-subsettable/。 - TarJae
2个回答

6

函数实际上是一种递归结构,我认为出于安全原因,他们决定不为[[函数提供默认方法。您可以使用as.list()获得更多类似列表的表示。

str(as.list(mean))
# $ x  : symbol 
# $ ...: symbol 
# $    : language UseMethod("mean")

因此,您得到的是参数列表和函数体。如果要直接获取函数体,可以执行以下操作:

body(mean)
body(mean)[[1]]

而这将返回主体作为可以子集的表达式。

所以函数基本上被存储为列表的列表,因此它们是递归的。


0

来自帮助文件?is.recursive:

大多数类型的对象都被视为递归。例外包括原子类型、NULL、符号(如as.name所给出的)、具有插槽的S4对象、外部指针以及从R中很少看到的弱引用和字节码,请参见typeof。

由于函数不是这些类型的对象之一,因此它不被视为原子性,而被视为递归性。

另一种看待这个问题的方式是,原子对象只能是单一类型的数据(整数、字符、数据的s4定义、指针等)。递归对象是一个可以在其中具有多种类型数据的对象,例如列表。函数可以在其中具有多种类型的数据(从哲学上讲,是一个过程而不是一组原子数据)。


谢谢您花时间回答,但我认为这并没有真正回答我的问题。我已经知道函数不在is.recursive的例外列表中 - 这是我提出问题的起点,因为它似乎应该在例外列表中。您说的“一个函数可以有多种类型的数据”是不正确的,据我所知- 一个函数只包含可解析的语言,没有其他东西。这与函数调用返回的对象完全不同,后者当然可以是递归的。 - dww
@dww:不,函数可以包含很多可解析语言之外的东西。MrFlick的答案展示了一些例子。另一个例子是数字或字符常量:当它们成为函数的一部分时,它们与它们在向量中的使用方式没有区别,例如body(mean)[[2]]是一个字符向量。 - user2554330
MrFlick的答案比我的好多了。 - Adam Sampson
另外一个需要注意的是,一个函数可以根据输入返回不同的结果。一个单一的函数有时可能会返回数字,但有时也可能会返回字符。如果你只看平均值,你可能会说一个函数实例只有一个结构和输出,但如果你只看一个列表,你也可以说这个单一的列表只有一种可能的结构。有些情况下,函数的输出并不是原子性的。 - Adam Sampson

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