scala foreach 和 map 初始值设定项

发布于 2024-09-09 02:48:46 字数 493 浏览 6 评论 0原文

刚刚看到一个有趣的可能性,可以在 Scala 中为 foreach 或 map 等高阶函数初始化代码块:

(1 to 3) map {
  val t = 5
  i => i * 5
}


(1 to 3) foreach {  
  val line = Console.readLine  
  i => println(line)  
}  

这是一些已记录的功能还是我应该避免这样的构造?我可以想象,“初始化”块进入构造函数,而闭包本身变成了 apply() 方法?

感谢帕特提出原始问题(http://extrabright.com /blog/2010/07/10/scala-question-regarding-readline

Just seen an interesting possibility to initialize code blocks in Scala for high order functions such as foreach or map:

(1 to 3) map {
  val t = 5
  i => i * 5
}


(1 to 3) foreach {  
  val line = Console.readLine  
  i => println(line)  
}  

Is this some documented feature or should I avoid such constructs? I could imagine, the "initialization" block comes into the constructor and the closure itself becomes an apply() method?

Thanks Pat for the original Question (http://extrabright.com/blog/2010/07/10/scala-question-regarding-readline)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

九局 2024-09-16 02:48:46

虽然所使用的功能并不罕见,但我承认这是一个相当奇怪的功能组合。基本技巧是 Scala 中的任何块都是一个表达式,其类型与块中最后一个表达式相同。如果最后一个表达式是函数,则意味着该块具有函数类型,因此可以用作“map”或“foreach”的参数。在这些情况下发生的情况是,当调用“map”或“foreach”时,将对块进行求值。该块计算为一个函数(在第一种情况下为 i=> i*5 ),然后将该函数映射到该范围。

此构造的一种可能用途是让块定义可变变量,并且每次调用时生成的函数都会改变变量。变量将被初始化一次,由函数关闭,并且每次调用函数时它们的值都会更新。

例如,这是计算前 6 个阶乘数的一种有点令人惊讶的方法

(1 to 6) map {
      var total = 1
      i => {total *= i;total}
    } 

(顺便说一句,很抱歉使用阶乘作为示例。它要么是阶乘,要么是斐波那契。函数式
编程协会规则。如果你对此有疑问,请与大厅里的男孩们一起讨论。)

让块返回函数的一个不太重要的原因是在块的前面定义辅助函数。例如,如果您的第二个示例是,

(1 to 3) foreach {  
  def line = Console.readLine  
  i => println(line)  
}

结果将是读取三行并每行回显一次,而您的示例则读取该行一次并回显三次。

While the features used are not uncommon, I'll admit is is a fairly odd combination of features. The basic trick is that any block in Scala is an expression, with type the same as the last expression in the block. If that last expression is a function, this means that the block has functional type, and thus can be used as an argument to "map" or "foreach" . What happens in these cases is that when "map" or "foreach" is called, the block is evaluated. The block evaluates to a function ( i=> i*5 in the first case ), and that function is then mapped over the range.

One possible use of this construct is for the block to define mutable variables, and the resulting function mutate the variables each time it is called. The variables will be initialized once, closed over by the function, and their values updated every time the function is called.

For example, here's a somewhat surprising way of calculating the first 6 factorial numbers

(1 to 6) map {
      var total = 1
      i => {total *= i;total}
    } 

(BTW, sorry for using factorial as an example. It was either that or fibonacci. Functional
Progamming Guild rules. You gotta problem with that, take it up with the boys down at the hall.)

A less imperative reason to have a block return a function is to define helper functions earlier in the block. For instance, if your second example were instead

(1 to 3) foreach {  
  def line = Console.readLine  
  i => println(line)  
}

The result would be that three lines were read and echoed once each, while your example had the line read once and echoed three times.

空心空情空意 2024-09-16 02:48:46

首先,原博客的评论“Scala Question About readLine ”帖子提及

line”是一个值,无法执行,它仅根据“Console.readLine”方法执行的结果分配一次。
它在您的闭包中使用的次数少于三次。
但如果将其定义为方法,则会执行3次:

(1 to 3) foreach {
  def line = Console.readLine
  i => println(line)
}

博客 Scala for Java Refugees Part 6: Getting Over Java 有一个关于高阶函数的有趣部分,包括:

Scala 在语法上为这些高阶函数提供了更大的灵活性。
在迭代调用中,我们创建一个完整的匿名方法,只是为了再次调用 println(String) 方法。
考虑到 println(String) 本身就是一个接受 String 并返回 Unit 的方法,人们会认为我们可以将其压缩一点。事实证明,我们可以:

iterate(a, println)

通过省略括号并仅指定方法名称,我们告诉 Scala 编译器我们想要使用 println 作为函数值,并将其传递给 iterate 方法。
因此,我们不是创建一个新方法来处理一组调用,而是传入一个已经完成我们想要的操作的旧方法。
这是 C 和 C++ 中常见的模式。事实上,将函数作为函数值传递的语法完全相同。似乎有些事情永远不会改变......

First, the comment of the original blog "Scala Question Regarding readLine" post mention

The “line” is a value and cannot be executed, it is assigned only once from the result of the “Console.readLine” method execution.
It is used less than three times in your closure.
But if you define it as a method, it will be executed three times:

(1 to 3) foreach {
  def line = Console.readLine
  i => println(line)
}

The blog Scala for Java Refugees Part 6: Getting Over Java has an interesting section on Higher Order function, including:

Scala provides still more flexibility in the syntax for these higher-order function things.
In the iterate invocation, we’re creating an entire anonymous method just to make another call to the println(String) method.
Considering println(String) is itself a method which takes a String and returns Unit, one would think we could compress this down a bit. As it turns out, we can:

iterate(a, println)

By omitting the parentheses and just specifying the method name, we’re telling the Scala compiler that we want to use println as a functional value, passing it to the iterate method.
Thus instead of creating a new method just to handle a single set of calls, we pass in an old method which already does what we want.
This is a pattern commonly seen in C and C++. In fact, the syntax for passing a function as a functional value is precisely the same. Seems that some things never change…

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文