Scala "<-" 用于理解

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3754089/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 02:25:50  来源:igfitidea点击:

Scala "<-" for comprehension

scalaloopscompiler-theoryfor-comprehension

提问by Felix

I have found that Scala always has a "natural explanation" to anything. Always something like "ohh, but that's just a function being called on this and that object with this and that parameter". In a sense, nothing is really compiler-magic as we know it from other languages.

我发现 Scala 总是对任何事情都有“自然的解释”。总是类似于“哦,但这只是在这个和那个对象上调用一个带有这个和那个参数的函数”。从某种意义上说,没有什么是真正的编译器魔法,正如我们从其他语言中所知道的那样。

My question is on the <-operator as used in the following code:

我的问题是关于以下代码中使用的<-运算符:

for(i <- 0 to 10) println(i)

In this example I can see it being rewritten to something like:

在这个例子中,我可以看到它被重写为:

0.to(10).foreach((i:Int)=>println(i))

but this doesn't explain how the igot carried into the anonymous function inside the foreach function. At the point where you write iit is not an object, and not yet a declared variable. So what is it, and how is it being carried over to the inside of foreach?

但这并不能解释i如何进入 foreach 函数内的匿名函数。在您编写i 时,它不是对象,也不是已声明的变量。那么它是什么,它是如何被转移到 foreach 内部的呢?

My guess is that I finally discovered something which is in fact compiler magic

我的猜测是我终于发现了一些实际上是编译器魔术的东西

Thanks for your time.

谢谢你的时间。

To clarify,my question is: how does the <- operator work in the 1st line of code since i is not an object on which it can be called as a function.

澄清一下我的问题是: <- 运算符如何在第一行代码中工作,因为 i 不是可以作为函数调用的对象。

采纳答案by Randall Schulz

<-is a language-defined keyword symbol, as is =>but in distinct contrast to ->(which is a defined symbol). Because it is part of the basic Scala grammar, it can be used to create bindings (for the iin your example) which is something that cannot be done by user-defined constructs.

<-是语言定义的关键字符号,=>->(这是一个定义的符号)形成鲜明对比。因为它是基本 Scala 语法的一部分,所以它可用于创建绑定(对于i您的示例中的 ),这是用户定义的构造无法完成的事情。

回答by missingfaktor

To augment Dave's answer, here is a translation schema for 'for-comprehensions' from Scala language specification:

为了补充 Dave 的答案,这里是 Scala 语言规范中“for-comprehensions”的翻译模式:

A comprehension for (enums) yield eevaluates expression efor each binding generated by the enumerators enums. An enumerator sequence always starts with a generator; this can be followed by further generators, value definitions, or guards.

A generator p <- eproduces bindings from an expression ewhich is matched in some way against pattern p. A value definition val p = ebinds the value name p(or several names in a pattern p) to the result of evaluating the expression e. A guard if econtains a boolean expression which restricts enumerated bindings.

The precise meaning of generators and guards is defined by translation to invocations of four methods: map, filter, flatMap, and foreach. These methods can be implemented in different ways for different carrier types.

The translation scheme is as follows. In a first step, every generator p <- e, where p is not irrefutable (§8.1) for the type of eis replaced by

 p <- e.filter { case p => true; case _ => false }

Then, the following rules are applied repeatedly until all comprehensions have been eliminated.

  • A for-comprehension for (p <- e) yield e0is translated to e.map { case p => e0 }.

  • A for-comprehension for (p <- e) e0is translated to e.foreach { case p => e0 }.

  • A for-comprehension for (p <- e; p0 <- e0 . . .) yield e00, where . . . is a (possibly empty) sequence of generators or guards, is translated to:
    e.flatMap { case p => for (p0 <- e0 . . .) yield e00 }.

  • A for-comprehension for (p <- e; p0 <- e0 . . .) e00where . . . is a (possibly empty) sequence of generators or guards, is translated to:
    e.foreach { case p => for (p0 <- e0 . . .) e00 }.

  • A generator p <- efollowed by a guard if gis translated to a single generator:
    p <- e.filter((x1, . . . , xn) => g )
    where x1, . . . , xnare the free variables of p.

  • A generator p <- efollowed by a value definition val p0 = e0is translated to the following generator of pairs of values, where xand x0are fresh names:

    val (p, p0) <- 
      for(x@p <- e) yield { val x0@p0 = e0; (x, x0) }
    

推导for (enums) yield e计算e枚举器枚举生成的每个绑定的表达式。一个枚举器序列总是以一个生成器开始;这之后可以是进一步的生成器、值定义或守卫。

生成器p <- ee以某种方式与模式匹配的表达式生成绑定p。值定义val p = e将值名称p(或模式中的多个名称p)绑定到表达式的计算结果e。守卫if e包含限制枚举绑定的布尔表达式。

发电机和警卫的确切含义是通过翻译定义为四种方法调用:mapfilterflatMap,和foreach。这些方法可以针对不同的载体类型以不同的方式实现。

翻译方案如下。在第一步中,每个生成器p <- e,其中 p 对于 的类型不是无可辩驳的(第 8.1 节)e被替换为

 p <- e.filter { case p => true; case _ => false }

然后,重复应用以下规则,直到消除所有理解。

  • 一个 for-comprehensionfor (p <- e) yield e0被翻译成e.map { case p => e0 }.

  • 一个 for-comprehensionfor (p <- e) e0被翻译成e.foreach { case p => e0 }.

  • 一个 for-comprehension for (p <- e; p0 <- e0 . . .) yield e00,其中 。. . 是发电机或防护装置的(可能为空)序列被翻译成:
    e.flatMap { case p => for (p0 <- e0 . . .) yield e00 }

  • 一个理解for (p <- e; p0 <- e0 . . .) e00where 。. . 是发电机或防护装置的(可能为空)序列被翻译成:
    e.foreach { case p => for (p0 <- e0 . . .) e00 }

  • p <- e后面跟着一个守卫的生成器if g被翻译成一个单独的生成器:
    p <- e.filter((x1, . . . , xn) => g )
    其中x1, 。. . ,xn是 的自由变量p

  • 的发电机p <- e,随后的值定义val p0 = e0被转换为双值,其中的下列发生器xx0新鲜的名称:

    val (p, p0) <- 
      for(x@p <- e) yield { val x0@p0 = e0; (x, x0) }
    

回答by Dave Griffith

In this case, it really is a bit of compiler magic. Translation from for-comprehension to filter/map/flatmap form is a special bit of desugaring, much like conversion of the special forms of update and apply methods.

在这种情况下,它确实有点编译器魔法。从 for-comprehension 到 filter/map/flatmap 形式的转换是一种特殊的脱糖,很像特殊形式的 update 和 apply 方法的转换。