2

我最近玩了一点 Groovy,惊讶地发现它不支持从闭包内部进行非本地返回。我对此感到非常惊讶,因为从使用 Smalltalk 开发的那一刻起,我一直认为这是正常情况。JDK8 lambdas 也不支持非本地返回,因为我很绝望。令人高兴的是,Scala 做到了。

问题 是闭包内部的非本地返回是闭包实现“成熟”的必要条件吗?或者我只是从 Smalltalk 中习惯了它,但事实并非如此。

代码说明

def list = list(1, 2, 3)
def value = list.forEach { each ->
    println(each)
        if(true)
             return each
    return 5
}

println(value)

我希望它打印“11”而不是“1235”。如果打印“1235”,至少它不应该编译。

4

4 回答 4

1

你想要的是list.findResult()而不是list.each()

def list = [1, 2, 3]
def value = list.findResult { each ->
  println(each)
  if(each)
    return each
  return 5
}
println(value)
// prints 1<newline>1
于 2013-07-15T21:38:19.637 回答
1

我也会投入我的两分钱。我认为没有一个明确的答案来解释是什么让闭包比另一个更成熟。但...

我认为 Smalltalkers 对他们的关闭感到非常自豪(理所当然地)。我曾经听说“Smalltalk 块对 lambda 的贡献比任何其他 lambda 运动语言都要多”。

大多数语言参考资料都有专门讨论“流控制”的部分。但 Smalltalk 是我所知道的唯一一种不仅敢于做“对象一路向下”而且“一路关闭”的语言。Smalltalk 中的所有流控制(循环、逻辑分支等)都是通过闭包完成的(或者至少看起来是这样做的,不要注意幕后的优化编译器!)。

于 2013-07-26T22:27:54.477 回答
1

找不到支持我的数据,但这是我的 0.02:闭包必须仅从自身返回,而不是从父调用者返回。父调用者的返回与 ruby​​ 的 blocks(1) 中使用的概念相同:两个块(被调用者和调用者)的控制/范围是相同的,而闭包应该是独立的。

scala 的实现方式是一种在 groovy 中实现的语法糖:通过抛出异常从闭包“返回”。

要从 groovy 中的闭包中“返回”,请坚持使用find,findAllfindResult(根据@jesseplymale 的回答):这些正在迭代正确的元素。

...

我不是 javascript 的专家,但他似乎同意我的观点:

// prints every item; the return is only from the function
[1, 2, 3, 4, 5].forEach( function(item) {
  console.log(item);
  return item;
}) 

Ruby,带有块和 lambda:

# block: prints "1" and stop iterating
def a()
  [1, 2, 3, 4, 5].each { |it|
    puts it
    return it 
  }
end

a()

传递一个块和一个 lambda 作为参数:

# this method receives a block/lambda and passes 
# it to the 'each' method from list
def b(block)
  [1, 2, 3, 4, 5].each &block
end

# this block fails with "unexpected return (LocalJumpError)"
#b(Proc.new { |it| puts it; return it; }) 

# this lambda keeps iterating and printing, even though 
# it has the return statement
b(lambda { |it| 
  puts it
  return it
})

(1):请注意,我不是 Ruby 的专家,这可能或多或少是错误的。

于 2013-07-16T13:06:33.300 回答
0

本地返回的词法闭包是实现 lambda 的最常用方法。实际上,Smalltalk/Ruby 块中的非本地返回是大多数其他语言的例外。一些 Smalltalks 甚至不会在词法范围内真正关闭块,因此您可能会质疑在多大程度上可以将块视为闭包

如果您从Scheme 转到Smalltalk/Ruby(就像我一样),您的问题可能正好相反。即:“Smalltalk 区块是否应该在本地返回被视为‘全面关闭’?”

即:非本地返回(主要)是为了简化处理控制结构,但它是一种特殊的机制。您可以将其称为转义延续,其中执行流程转义或跳转到另一个点。

非本地返回不是闭包的组成部分,只是一种特殊情况,可以独立实现(具体化延续、异常、其他特殊构造)。

请参阅这篇(旧)文章:http ://smalltalk.gnu.org/blog/s11001001/lexical-block-return-language-crux

这是关于闭包和返回的相关讨论:http: //lambda-the-ultimate.org/node/2009

[编辑]

发现了这个相关的问题:

“闭包”和“块”之间究竟有什么区别?

于 2014-12-01T00:32:08.937 回答