43

私は最近、scala用の新しい「仮想化」パターンマッチャーについてかなりの数の 言及を見てきました。それが実際に何であったかを説明するメモを逃しました...

4

2 に答える 2

32

仮想化された」パターンマッチャーは、既存のマッチャーを書き直したものです。これを行う動機は、2.10には関係のない、ポリモーフィックな組み込みDSLのパターンマッチングの仮想化をサポートすることでした。

Iulianが以下のコメントで述べているように、これはfor-comprehensionsのコンパイル方法と非常に似ています。コードを直接生成する代わりに、などに変換されforeachますmapfilterパターンマッチングは、一連のメソッド呼び出しに変換され、DSLが上書きする可能性があります。 。デフォルトの実装は現在のセマンティクスを尊重します。課題は、現在のセマンティクスと同じくらい効率的にすることです。Adriaanはこの目標に非常に近いようです。「仮想化」実装はより単純であり、現在の実装のいくつかのバグを修正します。

「ポリモーフィック組み込みDSL」は、JVMで実行されることを想定していないプログラムをscalaで作成する可能性があるという考えです。つまりscalac、プログラムが実行していることを説明する出力を生成します。その後、これを特定のアーキテクチャに対して再コンパイルできます。そのようなことはScalaDays2011で話題になっています。

この書き直しは、最終的には標準のscalaパターンマッチャーになります。古いパターンマッチャーは(私が理解しているように)保守不可能でした。

于 2011-12-16T13:35:14.267 に答える
8

悲しいことに、(唯一の)既存の答えはジューシーなビットが少なく、解説のリンクが壊れています。それで、ここにジュースを追加してみましょう。他の理由がなければ、将来実際に何かをすることにしたときの私自身の参照です。この答えは、私が行うすべてのグーグル検索の上にあるからです。

前述のように、仮想化されたパターンマッチャーは、Scalaコンパイラーがパターンマッチングを処理する方法を書き直したものです。それは多くの目的を果たし、その「仮想化」の部分は、仮想化されたscalaの取り組みの一部であることを意味します。この作業は、マクロとは少し逆です。コンパイル時に「実行」され、実行時に移動するものが必要です。

たとえば、スコープ内に適切な定義が存在する場合、次のようなステートメントがあります。

if (false) 1 else 2

バイトコードブランチとリテラルにコンパイルされる代わりに、またはリテラル「2」に最適化される代わりに、実際には次のステートメントとしてコンパイルされます。

__ifThenElse(false, 1, 2)

詳細とこれが役立つ例については、 scala仮想化ウィキを参照してください。

ただし、パターンマッチャーの書き換えには多くの目的があると言いました。もう1つの非常に重要な目標は、古いパターンマッチャーであったスパゲッティコード、フルケースまたはスペシャルケース、コーナーケース、バグを、より簡単に推論、拡張、改善できるものに変えることでした。この書き直しにより多くの問題が修正されたため、パターンマッチャーに関連する問題のサンプルコードを実行し、問題が機能するにつれて問題を「修正済み」としてマークする問題リストを確認しました。独自の新しいバグがありますが、規模ははるかに小さくなります。

現在、新しいパターンマッチャーがどのように機能するかについての情報はほとんどありませんが、基本的には、Optionモナドを使用してコンパイラーに「実装」されるいくつかのメソッド呼び出しに変換されます。次に、最適なバイトコードを生成する最適化フェーズに入ります。

-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およびMatchMonadInterfaceのscaladocsも参照してください。

免責事項:上記は、2.10.0以降のマスターブランチのScalaバージョンから抽出して実行したものであるため、違いがある可能性があります。しかし、私はそれをテストするための純粋な2.10.0または2.10.1環境に悲しいことに欠けていることに気づきました。

于 2013-05-13T16:19:21.337 に答える