简体   繁体   English

Scala:ForComprehension是一种功能性方法还是命令式?

[英]Scala: Is ForComprehension a Functional approach or imperative?

My collections: 我的收藏:

val l1 = List(1, 2, 3)
val l2 = List("A", "B", "C")

Here is an imperative approach: 这是一种必要的方法:

for {
    e1 <- l1
    e2 <- l2
  } {
    println(s"$e1 - $e2")
  }

And FP approach: 和FP方法:

l1 foreach { 
  a => l2 foreach { 
    b => println { 
      s"$a - $b" 
    } 
  } 
}

However, classic for loop represents a purely imperative style, I have some doubts about imperativeness of For Comprehension loop. 然而,经典的for循环代表了纯粹的命令式风格,我对For Comprehension循环的命令性有一些疑问。 So my question is: am I right that For Comprehension loop is from imperative style or not? 所以我的问题是:我是对的, For Comprehension循环来自命令式的风格与否?

A for-comprehension is a functional way of writing "imperative-looking" code. for-comprehension是编写“命令式”代码的功能性方法。

I'll cite Paul Chiusano and Runar Bjarnason from "Functional Programming in Scala" because I could never put it better: 我将引用“Scala中的函数编程”中的Paul Chiusano和Runar Bjarnason,因为我永远不会把它变得更好:

Page 89 第89页

Aren't imperative and functional programming opposites? 是不是命令式和函数式编程相反?

Absolutely not. 绝对不。 Remember, functional programming is simply programming without side effects. 请记住,函数式编程只是编程而没有副作用。 Imperative programming is about programming with statements that modify some program state, and as we've seen, it's entirely reasonable to maintain state without side effects. 命令式编程是关于使用修改某些程序状态的语句进行编程,正如我们所见,维持状态没有副作用是完全合理的。

Functional programming has excellent support for writing imperative programs, with the added benefit that such programs can be reasoned about equationally because they're referentially transparent. 函数式编程对编写命令式程序提供了极好的支持,还有一个额外的好处,即这些程序可以在等等方面进行推理,因为它们是引用透明的。


An example from the same page: 来自同一页面的示例:

val ns: Rand[List[Int]] =
  int.flatMap(x =>
    int.flatMap(y =>
      ints(x).map(xs =>
        xs.map(_ % y))))

It's not clear what's going on here. 目前尚不清楚这里发生了什么。 But since we have map and flatMap defined, we can use a for-comprehension to recover the imperative style: 但是由于我们定义了mapflatMap ,我们可以使用for-understanding来恢复命令式样式:

val ns: Rand[List[Int]] = for {
  x <- int
  y <- int
  xs <- ints(x)
} yield xs.map(_ % y)

This code is much easier to read (and write), and it looks like what it is—an imperative program that maintains some state. 这段代码更容易阅读(和写入),它看起来像是一个维持某种状态的命令式程序。 But it's the same code. 但它是相同的代码。 We get the next Int and assign it to x , get the next Int after that and assign it to y , then generate a list of length x , and finally return the list with all of its elements modulo y . 我们获取下一个Int并将其分配给x ,然后获取下一个Int并将其分配给y ,然后生成长度为x的列表,最后返回列表,其中所有元素都是模数y To facilitate this kind of imperative programming with for-comprehensions (or flatMaps ), we really only need two primitive State combinators—one for reading the state and one for writing the state. 为了利用for flatMaps (或flatMaps )来促进这种命令式编程,我们实际上只需要两个原始状态组合器 - 一个用于读取状态,一个用于写入状态。


One more from page 203: 来自第203页的另外一个:

We can see that a chain of flatMap calls (or an equivalent for-comprehension) is like an imperative program with statements that assign to variables, and the monad specifies what occurs at statement boundaries . 我们可以看到, flatMap调用链(或等效的for-comprehension)就像一个命令式程序,其中的语句分配给变量,而monad指定了语句边界处的内容

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM