R的Closure实现与其他函数式语言不同,这使得它的行为类似于c#等命令式语言

本文关键字:语言 类似于 命令式 实现 Closure 其他 函数 | 更新日期: 2023-09-27 18:11:15

R是一种函数式语言,但在以下情况下,它的行为像c#而不是f#。

在R

f <- function() x
x <- 15
f() // prints 15
x <- 20 // shadowing
f() // prints 20
用c#

int j = 15;
Action<string> funs = x => Console.WriteLine(j);
funs("foo"); // prints 15
j = 20; // mutate
funs("foo"); // prints 20
在f#

let x = 15
let f y = x
f() // prints 15
let x = 20 // shadowing, to mimic R (purely functional)
f() // prints 15, not 20

在R中,这个例子违背了我对"闭包关闭变量,通过值或引用"的理解。在c#中,闭包通过引用关闭变量。在f#中,这并不重要,因为变量是不可变的。但是在R中,闭包似乎只关闭了符号名,(当然不是通过值来关闭,因为它会改变;不是通过引用,因为变量是不可变的,它不会被改变,而是被遮蔽)。

那么,闭包关闭变量的方式有三种吗? 按值、按引用和按名称?在这种情况下,还有其他函数式语言的行为像R吗?

这里,动态查找在hadley的书中定义似乎解释了一点,但我找不到任何其他资源有术语"动态查找"。

R的Closure实现与其他函数式语言不同,这使得它的行为类似于c#等命令式语言

我不确定我完全理解你的问题,但也许这些例子有助于说明一个值是如何作用域的(但这些可能不是很好的例子!),但我强烈建议你阅读R语言定义的表达式部分的求值(事实上我可能应该去再读一遍):

# Define default value for x in function definition
f <- function( x = 15 ) x
f()
#[1] 15
# Assign value to x in .GlobalEnv
x <- 20
# But x is found in the environment of the function call because we already defined it there, so value we assigned inside the function is returned
f()
#[1] 15
# Now we pass an object, x to the function which causes it to search up the calling stack for an 'object' called x
f(x)
#[1] 20
# In this example we use 'get' to search for the object. In the help page it states:
# The default is to search from the current environment of the call to 'get'
f <- function() get( "x" )
f()
[1] 20
# But we can specify an environment to search in
# In this case we specify an environment where x was not defined
# and it is not found
f<- function() { pos <- sys.nframe()+1 ; get("x" ,  envir = as.environment(pos) ) }
f()
#Error in get("x", envir = as.environment(2)) : object 'x' not found

来自Scheme,我没有看到混乱。

。,使用chibi-scheme (R7RS):

$ chibi-scheme
> (define f (lambda () x))
WARNING: reference to undefined variable: x
> (define x 15)
> (f)
15
> (define x 20)
> (f)
20

对于任何兼容的Scheme版本都应该是相同的(至少在Guile和MIT/GNU Scheme中有效)。repl可能与编译器不同,但即使您编写了上面的代码,并且编译了,它也会使用符号表并在解析文件后解析引用。它仍然可以工作。

f引用了变量x指定的内存位置上的值。当您执行f <- 15f <- 20时,您更新而不是引用或位置。

我可能是错的(或者使用不正确的技术术语),但我仍然觉得这并不奇怪。