什么是 scala 的实验性虚拟模式匹配器?

发布于 2024-12-21 16:14:14 字数 462 浏览 3 评论 0原文

我见过不少 一些 提及最近出现了 scala 的新“虚拟化”模式匹配器。我错过了解释它实际上是什么的备忘录......

I've seen quite a few mentions recently of the new "virtualized" pattern matcher for scala. I missed the memo explaining what it actually was...

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

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

发布评论

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

评论(2

太阳公公是暖光 2024-12-28 16:14:14

“虚拟化”模式匹配器是现有匹配器的重写。这样做的动机是支持多态嵌入式 DSL 模式匹配的虚拟化,与 2.10 无关。

正如 Iulian 在下面的评论中所说:它与 for 推导式的编译方式非常相似:它们不是直接生成代码,而是翻译为 foreachmapfilter 等。然后,模式匹配可以转换为一系列方法调用,DSL 可以覆盖这些方法调用。默认实现将尊重当前语义,挑战是使其与当前语义一样高效。看来阿德里安已经非常接近这个目标了。 “虚拟化”实现更简单,并且修复了当前实现中的几个错误。

“多态嵌入式 DSL”是一种想法,即人们可以用 scala 编写不应该在 JVM 上运行的程序。也就是说,scalac 将产生一个描述程序正在执行的操作的输出。然后可以针对特定架构重新编译。这些事情已经在 ScalaDays 2011 上讨论过

这个重写最终将成为标准的 scala 模式匹配器。旧的模式匹配器(据我所知)无法维护。

The "virtualized" pattern matcher is a rewrite of the existing matcher. The motivation for doing this was to support virtualization of pattern matching for the polymorphic embedded DSLs, not relevant for 2.10.

As Iulian says in the comments below: It's very similar to how for-comprehensions are compiled: instead of directly generating code, they are translated to foreach, map, filter etc. Pattern matching could then be translated to a series of method calls, that DSLs could overwrite. The default implementation will respect the current semantics, and the challenge is to make it as efficient as the current one. It seems Adriaan is very close to this goal. The 'virtualized' implementation is simpler, and fixes several bugs in the current implementation.

The "polymorphic embedded DSLs" are the idea that one might write programs in scala that are not supposed to be run on the JVM. That is, scalac will produce an output which describes what the program is doing. This may then be re-compiled against a specific architecture. Such things have been talked about at ScalaDays 2011.

This rewrite will eventually become the standard scala pattern matcher. The old pattern matcher was (as I understand it) unmaintainable.

撑一把青伞 2024-12-28 16:14:14

可悲的是,(唯一)现有的答案缺乏有趣的内容,而且评论上的链接也被破坏了。因此,让我尝试在这里添加一些内容,如果没有其他原因,当我真正决定将来用它做某事时,我自己的参考,因为这个答案位于我所做的每次谷歌搜索的顶部。

如前所述,虚拟化模式匹配器重写了 Scala 编译器处理模式匹配的方式。它有很多用途,其中的“虚拟化”部分意味着它是虚拟化 scala 工作的一部分。这种努力与宏有点相反:它需要在编译时“运行”的东西,然后移动到运行时。

例如,考虑到作用域中存在正确的定义,像这样的语句:

if (false) 1 else 2

而不是被编译为字节码分支和文字,甚至优化为文字“2”,实际上被编译为以下语句:

__ifThenElse(false, 1, 2)

请参阅< a href="https://github.com/TiarkRompf/scala-virtualized/wiki" rel="noreferrer">scala 虚拟化 wiki 了解更多信息和一些有用的示例。

然而,我说过,模式匹配器重写有很多用途。另一个非常重要的目标是将意大利面条式代码(即旧的模式匹配器)(完整或特殊以及极端情况和错误)转变为可以更轻松地推理、扩展和改进的代码。这次重写解决了如此多的问题,以至于人们只需浏览问题列表,运行与模式匹配器相关的问题的示例代码,并将问题标记为“已修复”。它确实有自己的新错误,但规模要小得多。

现在,关于新模式匹配器如何工作的信息很少,但基本上,它会转换为一些方法调用,这些方法调用在编译器中使用 Option monad“实现”。然后进入优化阶段,生成最佳字节码。

可以引入您自己的匹配器,尽管它被锁定在 -Xexperimental 标志后面。尝试使用从 Scala 的测试套件复制的以下代码(带或不带该标志):

trait Intf {
 type Rep[+T]
 type M[+T] = Rep[Maybe[T]]

 val __match: Matcher
 abstract class Matcher {
   // runs the matcher on the given input
   def runOrElse[T, U](in: Rep[T])(matcher: Rep[T] => M[U]): Rep[U]

   def zero: M[Nothing]
   def one[T](x: Rep[T]): M[T]
   def guard[T](cond: Rep[Boolean], then: => Rep[T]): M[T]
   def isSuccess[T, U](x: Rep[T])(f: Rep[T] => M[U]): Rep[Boolean] // used for isDefinedAt
 }

 abstract class Maybe[+A] {
   def flatMap[B](f: Rep[A] => M[B]): M[B]
   def orElse[B >: A](alternative: => M[B]): M[B]
 }

 implicit def proxyMaybe[A](m: M[A]): Maybe[A]
 implicit def repInt(x: Int): Rep[Int]
 implicit def repBoolean(x: Boolean): Rep[Boolean]
 implicit def repString(x: String): Rep[String]

 def test = 7 match { case 5 => "foo" case _ => "bar" }
}

trait Impl extends Intf {
 type Rep[+T] = String

 object __match extends Matcher {
   def runOrElse[T, U](in: Rep[T])(matcher: Rep[T] => M[U]): Rep[U] = ("runOrElse("+ in +", ?" + matcher("?") + ")")
   def zero: M[Nothing]                                             = "zero"
   def one[T](x: Rep[T]): M[T]                                      = "one("+x.toString+")"
   def guard[T](cond: Rep[Boolean], then: => Rep[T]): M[T]          = "guard("+cond+","+then+")"
   def isSuccess[T, U](x: Rep[T])(f: Rep[T] => M[U]): Rep[Boolean]  = ("isSuccess("+x+", ?" + f("?") + ")")
 }

 implicit def proxyMaybe[A](m: M[A]): Maybe[A] = new Maybe[A] {
   def flatMap[B](f: Rep[A] => M[B]): M[B]                          = m + ".flatMap(? =>"+ f("?") +")"
   def orElse[B >: A](alternative: => M[B]): M[B]                   = m + ".orElse("+ alternative +")"
 }

 def repInt(x: Int): Rep[Int] = x.toString
 def repBoolean(x: Boolean): Rep[Boolean] = x.toString
 def repString(x: String): Rep[String] = x
}

object Test extends Impl with Intf with App {
  println(test)
}

不带标志的结果正是您所期望的:

scala> Test.main(null)
bar

但是,使用 -Xexperimental 时,会得到替代的匹配“engine”已编译:

scala> Test.main(null)
runOrElse(7, ?guard(false,?).flatMap(? =>one(foo)).orElse(one(bar)))

有关更多信息,另请参阅 PatternMatchingMatchMonad 接口

免责声明:以上是从 2.10.0 之后的 master 分支上的 Scala 版本中提取并运行的,因此可能存在差异。但遗憾的是,我发现自己缺少一个纯粹的 2.10.0 或 2.10.1 环境来测试它。

Sadly, the (sole) existing answer is low on juicy bits, and the links on the commentary are broken. So let me try to add some juice here, for, if no other reason, my own reference when I actually decide to do something with it in the future, seeing as this answer is on top of every google search I do.

The virtualized pattern matcher, as mentioned, is a rewrite of how the Scala compiler handles pattern matching. It served many purposes, with the "virtualization" part of it meaning it is part of the virtualized scala effort. That effort is a bit the opposite of macros: it takes things that are "run" at compile time, and move then to run time.

For example, given the presence of the proper definition in scope, a statement like this:

if (false) 1 else 2

instead of being compiled to bytecode branches and literals, or even optimized to the literal "2", actually gets compiled as the following statement:

__ifThenElse(false, 1, 2)

Please see the scala virtualized wiki for more information and some examples of what this can be useful for.

I said, however, that the pattern matcher rewrite served many purposes. One other very important goal was to turn the spaghetti code that was the old pattern matcher, full or special and corner cases and bugs, into something that can be reasoned with, extended and improved more easily. This rewrite fixed so many problems that people just went through the issues list running sample code for issues related to the pattern matcher and marking the issues as "fixed" as they worked. It does have new bugs of its own, but on a much, much smaller scale.

Now, there's very little information about how the new pattern matcher works, but, basically, it translates into a few method calls which are "implemented" in the compiler with the Option monad. That then goes into an optimization phase that produces optimal bytecode.

It is possible to introduce your own matcher, though that's locked behind an -Xexperimental flag. Try the following code, copied from Scala's test suite, with and without that flag:

trait Intf {
 type Rep[+T]
 type M[+T] = Rep[Maybe[T]]

 val __match: Matcher
 abstract class Matcher {
   // runs the matcher on the given input
   def runOrElse[T, U](in: Rep[T])(matcher: Rep[T] => M[U]): Rep[U]

   def zero: M[Nothing]
   def one[T](x: Rep[T]): M[T]
   def guard[T](cond: Rep[Boolean], then: => Rep[T]): M[T]
   def isSuccess[T, U](x: Rep[T])(f: Rep[T] => M[U]): Rep[Boolean] // used for isDefinedAt
 }

 abstract class Maybe[+A] {
   def flatMap[B](f: Rep[A] => M[B]): M[B]
   def orElse[B >: A](alternative: => M[B]): M[B]
 }

 implicit def proxyMaybe[A](m: M[A]): Maybe[A]
 implicit def repInt(x: Int): Rep[Int]
 implicit def repBoolean(x: Boolean): Rep[Boolean]
 implicit def repString(x: String): Rep[String]

 def test = 7 match { case 5 => "foo" case _ => "bar" }
}

trait Impl extends Intf {
 type Rep[+T] = String

 object __match extends Matcher {
   def runOrElse[T, U](in: Rep[T])(matcher: Rep[T] => M[U]): Rep[U] = ("runOrElse("+ in +", ?" + matcher("?") + ")")
   def zero: M[Nothing]                                             = "zero"
   def one[T](x: Rep[T]): M[T]                                      = "one("+x.toString+")"
   def guard[T](cond: Rep[Boolean], then: => Rep[T]): M[T]          = "guard("+cond+","+then+")"
   def isSuccess[T, U](x: Rep[T])(f: Rep[T] => M[U]): Rep[Boolean]  = ("isSuccess("+x+", ?" + f("?") + ")")
 }

 implicit def proxyMaybe[A](m: M[A]): Maybe[A] = new Maybe[A] {
   def flatMap[B](f: Rep[A] => M[B]): M[B]                          = m + ".flatMap(? =>"+ f("?") +")"
   def orElse[B >: A](alternative: => M[B]): M[B]                   = m + ".orElse("+ alternative +")"
 }

 def repInt(x: Int): Rep[Int] = x.toString
 def repBoolean(x: Boolean): Rep[Boolean] = x.toString
 def repString(x: String): Rep[String] = x
}

object Test extends Impl with Intf with App {
  println(test)
}

The result without the flag is just what you'd expect:

scala> Test.main(null)
bar

With -Xexperimental, however, the alternative matching "engine" gets compiled:

scala> Test.main(null)
runOrElse(7, ?guard(false,?).flatMap(? =>one(foo)).orElse(one(bar)))

See also, for more information, the scaladocs for PatternMatching and the MatchMonadInterface.

Disclaimer: the above was extract and ran from a Scala version on the master branch, after 2.10.0, so there may be differences. I find myself sadly lacking in a pure 2.10.0 or 2.10.1 environment to test it out, though.

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