【问题标题】:How to express [42 | x == y] with for comprehensions?如何表达 [42 | x == y] 与 for 理解?
【发布时间】:2013-05-06 05:36:25
【问题描述】:

我有一些代码在其中生成多个列表(通过理解),然后将它们连接起来。但是,有些单元素列表不起作用。在 Haskell 中,我会做类似的事情

[42 | i == j]

相当于

(do guard (i == j)
    return 42) :: [Int]

(guard (i == j) >>= \_ -> return 1) :: [Int]

我在 Scala 中尝试过

for (if i == j) yield 42

但它说“简单模式的非法开始”。

In an answer to what Scala's yield is 作者说'Scala 的“for comprehensions”等同于 Haskell 的“do”notation'。

此外,在Scala website 上,它说“理解的形式为 for (enums) yield e,其中 enums 是指以分号分隔的枚举器列表。枚举器要么是生成器,要么引入了新变量,或者它是一个过滤器”。但显然,情况并非如此,因为过滤器似乎只允许在 生成器之后使用。

我现在使用

if (i == j) List(42) else Nil

对于这种特殊情况,我可能不喜欢 for 理解语法,而是使用 if-then-else。在 Haskell 中,由于与数学集合构建符号的相似性,它看起来相当不错。

我的问题不是关于风格,而是更多关于技术细节:为什么 Haskell 和 Scala 在这个特定案例中存在差异?为什么for (if i == j) yield 42 不起作用?

【问题讨论】:

  • 我很惊讶 Haskell 中的列表理解确实有效。我本来希望在理解中也需要至少一个生成器。

标签: scala list-comprehension for-comprehension


【解决方案1】:

[42 | i == j] 的最接近等价物可能是 for (x <- List(42) if i == j) yield x

for (if i == j) yield 42 是非法的,因为过滤器(if 部分)必须跟随某个生成器(在我的示例中为 x <- List(42))。

Scala language specification 状态(6.19 For Comprehensions and For Loops):

语法:

Expr1       ::= ‘for’ (‘(’ Enumerators ‘)’ | ‘{’ Enumerators ‘}’)
                  {nl} [‘yield’] Expr
Enumerators ::= Generator {semi Enumerator}
Enumerator  ::= Generator
                | Guard
                | ‘val’ Pattern1 ‘=’ Expr
Generator   ::= Pattern1 ‘<-’ Expr [Guard]
Guard       ::= ‘if’ PostfixExpr

如您所见,Enumerators 中至少需要一个生成器。

编辑

顺便说一句,我认为 if (i == j) List(42) else Nil 是正确的做法,因为它不是 Haskell。它很干净而且很可能更快,因为它只构建一次列表并且不调用任何其他方法。

我的例子被编译器翻译成List(42) withFilter (x =&gt; i == j) map (x =&gt; x)(它实际上可能被优化了,我不确定)并且可以缩写为List(42) filter (x =&gt; i == j)。您可以看到,它构造了初始列表,然后调用了一个创建新列表的方法,并且该方法采用匿名函数,在 Scala 中它也是一个对象(但可能它也被优化了)。我认为做这么简单的工作效率很低。

【讨论】:

  • 我暂时接受了这个答案,但我仍然对为什么存在差异感兴趣,或者:Scala 中的(guard (i == j) &gt;&gt;= \_ -&gt; return 1) :: [Int] 是什么?我用那个 Haskell sn-p 更新了这个问题。我认为 som-snytt 的回答对此有一些暗示。
猜你喜欢
  • 2021-12-17
  • 1970-01-01
  • 2021-03-16
  • 2021-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-08
  • 1970-01-01
相关资源
最近更新 更多