for 理解中的模式匹配分配如何转化为一元操作?

Posted

技术标签:

【中文标题】for 理解中的模式匹配分配如何转化为一元操作?【英文标题】:How do pattern match assignments in for comprehensions translate into monadic operations? 【发布时间】:2021-12-02 22:18:05 【问题描述】:

我熟悉 Scala 的 for 推导式只是单元操作(mapwithFilterforeachflatMap)的语法糖这一概念,并且在 this popular answer 中描述了脱糖。

按照这种逻辑,我惊讶地发现,当使用模式匹配作为 for 理解的赋值部分的一部分时,当模式与元素不匹配时,不会抛出 MatchError。而是过滤掉不匹配的元素:

case class Account(id: String, role: String)
val accounts = Set(Account("a", "ADMIN"), Account("b", "USER"), Account("c", "ADMIN"), Account("d", "USER"), Account("e", "USER"))

val adminIds = for (Account(id, "ADMIN") <- accounts) yield id
// Set("a", "c") (no MatchError on Account("b", "USER")!

我本来希望这种理解可以翻译成这样的:

val adminIds = accounts.map  case Account(id, "ADMIN") => id 

// or maybe
val adminIds = accounts.map  account =>
  val Account(id, "ADMIN") = account
  id


当然,那些会抛出MatchError。相反,它似乎更类似于:

val adminIds = accounts.collect  case Account(id, "ADMIN") => id 

但是,我从未见过任何提及 for 理解将糖分转化为 collect 调用。

那么这是如何在幕后完成的呢?

【问题讨论】:

不是collect是对withFilter的调用 在幕后,您的理解翻译为:val adminIds = accounts.withFilter case Account(id: String, "ADMIN") =&gt; true; case _ =&gt; false .map( case Account(id: String, "ADMIN") =&gt; id ) 换句话说,由于集合的严格性(如链接答案中所述),它使用withFilter。这会导致按需过滤。 @m_vemuri 您不妨发布此评论作为答案! @CarloPrato 看起来像是有人从我这里偷走了这个特权。但我会继续发布它。我希望我的最初努力能得到回报。 【参考方案1】:

添加我的答案,最初是作为评论发布的。

在幕后,你的理解被翻译成:

val adminIds = accounts.withFilter 
  case Account(id: String, "ADMIN") => true;
  case _ => false
.map(
  case Account(id: String, "ADMIN") => id
)

换句话说,它使用的是withFilter

总结 linked answer,withFilter 是在 scala 2.8 中引入的,适用于严格集合(如 List,而不是像 Stream 这样的非严格集合。)而不是返回一个新的过滤集合,它会按需过滤。

这就是为什么您在运行代码时不会注意到MatchError

【讨论】:

啊,我明白了。很高兴知道有这种默认情况。【参考方案2】:

如果您将该代码放入 Intellij 和 desugar 之类的 IDE 中,您将得到类似的结果

val adminIds: Set[String] = accounts.withFilter  case Account(id: String, "ADMIN") => true; case _ => false .map( case Account(id: String, "ADMIN") => id )

这不是收集电话

【讨论】:

以上是关于for 理解中的模式匹配分配如何转化为一元操作?的主要内容,如果未能解决你的问题,请参考以下文章

为啥必须在scala的for循环中为模式匹配定义过滤器?

关于字符串精确匹配

数据结构关于串的KMP算法的理解高手请进

乘法逆元通俗易懂的理解方法

Perl编程-6正则表达式--替换+转化

kmp算法及应用