【问题标题】:R implemenation of Closure differs from other functional languages, which makes it behave like imperative language such as C#?Closure 的 R 实现不同于其他函数式语言,这使得它的行为类似于 C# 等命令式语言?
【发布时间】:2013-04-23 05:51:29
【问题描述】:

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 中,似乎闭包只关闭符号名称,(确定不是通过值,因为它确实改变了;不是通过引用,因为变量是不可变的,所以它不是变异而是被遮蔽)。

那么,闭包有 3 种方式关闭变量,按值、按引用和按名称

在这种情况下,是否还有其他函数式语言的行为类似于 R?

这里,hadley 的 book 中定义的 Dynamic Lookup 似乎可以解释一下,但我找不到任何其他具有“动态查找”一词的资源。

【问题讨论】:

  • 您的 F# 示例是错误的。这不是为 x 分配一个新值,它实际上是在声明一个名为 x 的新变量,它将前一个变量隐藏在当前范围内。如果您将 x 声明为可变的,然后使用 &lt;- 分配给它,那么它的工作方式与 C# 相同。
  • @mydogisbox 的目的是,我正在做阴影,而不是 F# 中的赋值,以模仿纯粹的函数式语言。顺便说一句,我不是在将 F# 与 C# 进行比较,而是将 F# 与 R 进行比较,将 C# 与 R 进行比较。
  • 我不确定如何回答这个问题,而不是简单地向您引用 R 的关于其实现词法作用域的文档。
  • @joran 所有 3 种语言都是词法范围
  • 但是仅仅因为它们都声称是“词法作用域”并不意味着在实现上不会有一些小的差异。它们可能相似,但毕竟它们是不同的语言。

标签: c# r f# functional-programming closures


【解决方案1】:

我不确定我是否完全理解您的问题,但也许这些示例有助于说明值的范围(但这些可能不是很好的示例!)但我强烈建议您阅读@987654321 @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

【讨论】:

  • 谢谢,我明白它是如何工作的。我只是觉得奇怪的是,闭包没有将值绑定到定义时的变量,就像所有其他函数式语言一样。我原以为这是函数式语言的“规则”。
  • 对不起,我把你的问题理解为你需要一些插图。这是一个我觉得很难掌握的主题(一些知识渊博的人可能会指出我没有掌握)。无论如何,它会绑定该值,但仅限于指定的环境。这取决于评估的内容和评估的位置。这确实有道理。每个对象都有隐藏的属性,其中之一是创建对象的环境。
【解决方案2】:

来自 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 &lt;- 15f &lt;- 20 时,您更新的是,而不是引用或位置。

我可能是错的(或使用了不正确的技术术语),但我仍然觉得这并不令人惊讶。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-23
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 1970-01-01
    • 2011-12-21
    相关资源
    最近更新 更多