2 回答
“虚拟化”模式匹配器是对现有匹配器的重写。这样做的动机是支持多态嵌入式 DSL的模式匹配虚拟化,与 2.10 无关。
正如 Iulian 在下面的评论中所说:它与 for-comprehensions 的编译方式非常相似:不是直接生成代码,而是将它们转换为foreach
,map
等filter
。然后可以将模式匹配转换为 DSL 可以覆盖的一系列方法调用. 默认实现将尊重当前语义,挑战在于使其与当前语义一样高效。看来阿德里安非常接近这个目标。“虚拟化”实现更简单,并修复了当前实现中的几个错误。
“多态嵌入式 DSL”是一种想法,即人们可能会在 scala 中编写不应该在 JVM 上运行的程序。也就是说,scalac
将产生一个描述程序正在做什么的输出。然后可以针对特定架构重新编译。在 ScalaDays 2011 上已经讨论过这样的事情。
这种重写最终将成为标准的 scala 模式匹配器。旧的模式匹配器(据我所知)无法维护。
可悲的是,(唯一)现有的答案很少,评论上的链接也被破坏了。所以让我在这里尝试添加一些果汁,如果没有其他原因,我自己的参考,当我将来真正决定用它做某事时,因为这个答案是我所做的每个谷歌搜索的顶部。
如前所述,虚拟化模式匹配器是对 Scala 编译器如何处理模式匹配的重写。它有很多用途,其中的“虚拟化”部分意味着它是虚拟化 scala 工作的一部分。这种努力与宏有点相反:它需要在编译时“运行”的东西,然后移动到运行时。
例如,鉴于范围内存在正确的定义,这样的语句:
if (false) 1 else 2
而不是编译为字节码分支和文字,甚至优化为文字“2”,实际上被编译为以下语句:
__ifThenElse(false, 1, 2)
请参阅scala virtualized 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
时,会编译替代匹配的“引擎”:
scala> Test.main(null)
runOrElse(7, ?guard(false,?).flatMap(? =>one(foo)).orElse(one(bar)))
有关更多信息,另请参阅 PatternMatching 的scaladocs和MatchMonadInterface。
免责声明:以上内容是从 2.10.0 之后的 master 分支上的 Scala 版本中提取和运行的,因此可能存在差异。不过,我发现自己很遗憾缺乏纯 2.10.0 或 2.10.1 环境来测试它。