J'ai vu un certain nombre quelques mentionne récemment de la nouvelle "virtualisé" pattern matcher pour scala. J'ai manqué le mémo expliquant ce que c'était réellement...
Réponses
Trop de publicités?El "virtualisé" pattern matcher est une réécriture du matcher existant. La motivation de cette réécriture était de prendre en charge la virtualisation du filtrage de motifs pour le système de gestion de l'information. DSL embarqués polymorphes non pertinent pour 2.10.
Comme le dit Iulian dans les commentaires ci-dessous : C'est très similaire à la façon dont les for-comprehensions sont compilées : au lieu de générer directement du code, elles sont traduites en foreach
, map
, filter
etc. Le filtrage pourrait alors être traduit en une série d'appels de méthodes, que les DSL pourraient écraser. L'implémentation par défaut respectera la sémantique actuelle, et le défi est de la rendre aussi efficace que l'actuelle. Il semble qu'Adriaan soit très proche de cet objectif. L'implémentation "virtualisée" est plus simple, et corrige plusieurs bogues dans l'implémentation actuelle.
Les "DSL polymorphes intégrés" sont l'idée que l'on peut écrire des programmes en Scala qui ne sont pas censés être exécutés sur la JVM. C'est-à-dire, scalac
produira une sortie qui décrit ce que fait le programme. Celui-ci peut ensuite être recompilé pour une architecture spécifique. De telles choses ont été évoqués lors des ScalaDays 2011 .
Cette réécriture deviendra éventuellement le pattern matcher standard de Scala. L'ancien pattern matcher était (d'après ce que j'ai compris) non maintenable.
Malheureusement, la (seule) réponse existante ne contient pas beaucoup d'éléments intéressants, et les liens du commentaire sont cassés. Permettez-moi donc d'essayer d'ajouter un peu de jus ici, pour, si ce n'est pour une autre raison, ma propre référence lorsque je déciderai d'en faire quelque chose à l'avenir, vu que cette réponse est en tête de toutes les recherches Google que je fais.
Comme nous l'avons mentionné, le sélecteur de motifs virtualisé est une réécriture de la façon dont le compilateur Scala gère la correspondance des motifs. Il a servi à plusieurs fins, la partie "virtualisation" signifiant qu'il fait partie de l'effort de virtualisation de Scala. Cet effort est un peu l'opposé des macros : il prend des choses qui sont "exécutées" au moment de la compilation, et les déplace au moment de l'exécution.
Par exemple, étant donné la présence de la définition appropriée dans la portée, une déclaration comme celle-ci :
if (false) 1 else 2
au lieu d'être compilé en branches et en littéraux de bytecode, ou même optimisé au littéral "2", est en fait compilé comme l'instruction suivante :
__ifThenElse(false, 1, 2)
Veuillez consulter le wiki scala virtualisé pour plus d'informations et quelques exemples de ce à quoi cela peut servir.
J'ai dit, cependant, que la réécriture du correcteur de motif servait de nombreux objectifs. Un autre objectif très important était de transformer le code spaghetti qu'était l'ancien pattern matcher, plein de cas particuliers et de bogues, en quelque chose qui peut être raisonné, étendu et amélioré plus facilement. Cette réécriture a corrigé tellement de problèmes que les gens ont simplement parcouru la liste des problèmes en exécutant des exemples de code pour les problèmes liés au correcteur de motifs et en marquant les problèmes comme "corrigés" au fur et à mesure qu'ils fonctionnaient. Il y a de nouveaux bogues, mais à une échelle beaucoup, beaucoup plus petite.
Il existe très peu d'informations sur le fonctionnement du nouveau sélecteur de motifs, mais, en gros, il se traduit par quelques appels de méthodes qui sont "implémentés" dans le compilateur avec l'attribut Option
monad. Il entre ensuite dans une phase d'optimisation qui produit un bytecode optimal.
Il est possible d'introduire votre propre matcheur, bien qu'il soit verrouillé derrière un système de contrôle de la qualité. -Xexperimental
drapeau. Essayez le code suivant, copié de la suite de tests de Scala, avec et sans ce drapeau :
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)
}
Le résultat sans le drapeau est exactement ce que l'on attend :
scala> Test.main(null)
bar
Avec -Xexperimental
Cependant, l'alternative "moteur" est compilée :
scala> Test.main(null)
runOrElse(7, ?guard(false,?).flatMap(? =>one(foo)).orElse(one(bar)))
Voir aussi, pour plus d'informations, les scaladocs pour PatternMatching y el MatchMonadInterface .
Avertissement : ce qui précède a été extrait et exécuté à partir d'une version de Scala sur la branche master, après la 2.10.0, donc il peut y avoir des différences. Je manque cruellement d'un environnement 2.10.0 ou 2.10.1 pur pour le tester, cependant.