Что такое экспериментальный виртуальный шаблонный образец в Scala? - PullRequest
43 голосов
/ 16 декабря 2011

Я видел довольно несколько , упоминающих недавно о новом "виртуализированном" шаблоне сопоставления для scala. Я пропустил записку, объясняющую, что это было на самом деле ...

Ответы [ 2 ]

32 голосов
/ 16 декабря 2011

"виртуализированный" шаблон сопоставления - это перезапись существующего сопоставителя.Мотивация для этого заключалась в поддержке виртуализации сопоставления с образцом для полиморфных встроенных DSL , не относящихся к 2.10.

Как Юлиан говорит в комментариях ниже: Это очень похоже накак скомпилированы фор-понимания: вместо того, чтобы напрямую генерировать код, они переводятся в foreach, map, filter и т. д. Сопоставление с образцом можно затем преобразовать в серию вызовов методов, которые DSL могут перезаписывать.Реализация по умолчанию будет учитывать текущую семантику, и задача состоит в том, чтобы сделать ее такой же эффективной, как и текущая.Кажется, Адриан очень близок к этой цели.«Виртуализированная» реализация проще и исправляет несколько ошибок в текущей реализации.

«Полиморфные встроенные DSL» - это идея, что можно писать программы в scala, которые не должны запускаться наJVM.То есть scalac выдаст вывод, который описывает, что делает программа.Затем это может быть перекомпилировано для конкретной архитектуры.О таких вещах говорили на ScalaDays 2011 .

Это переписывание в конечном итоге станет стандартным сопоставителем шаблонов scala.Старое сопоставление с образцом было (насколько я понимаю) не поддерживаемым.

8 голосов
/ 13 мая 2013

К сожалению, (единственного) существующего ответа мало на сочные биты, и ссылки в комментарии не работают. Итак, позвольте мне попытаться добавить сюда немного сока, если не по какой-либо другой причине, это моя собственная справочная информация, когда я на самом деле решу что-то сделать с этим в будущем, учитывая, что этот ответ находится в верхней части каждого поиска в Google, который я выполняю.

Виртуализированное сопоставление с образцом, как уже упоминалось, представляет собой переписывание того, как компилятор Scala обрабатывает сопоставление с образцом. Он служил многим целям, с частью «виртуализации», означающей, что он является частью виртуализированного проекта scala. Это усилие немного противоположно макросам: оно берет вещи, которые «запускаются» во время компиляции, а затем перемещаются во время выполнения.

Например, учитывая наличие правильного определения в области видимости, выражение вроде этого:

if (false) 1 else 2

вместо того, чтобы компилироваться в ветви и литералы байт-кода или даже оптимизироваться до литерала "2", фактически компилируется как следующий оператор:

__ifThenElse(false, 1, 2)

Пожалуйста, смотрите scala virtualized wiki для получения дополнительной информации и некоторых примеров того, для чего это может быть полезно.

Однако я сказал, что переписывание шаблонов соответствовало многим целям. Еще одна очень важная цель состояла в том, чтобы превратить код спагетти, который был старым сопоставителем шаблонов, полными или специальными и угловыми случаями и ошибками, во что-то, что можно легче обосновывать, расширять и улучшать. Эта перезапись исправила так много проблем, что люди просто просмотрели список проблем, запустив пример кода для проблем, связанных с сопоставителем шаблонов и пометив проблемы как «исправленные» в процессе работы. У него есть новые ошибки, но в гораздо меньшем масштабе.

Теперь очень мало информации о том, как работает новый сопоставитель шаблонов, но, по сути, он преобразуется в несколько вызовов методов, которые «реализуются» в компиляторе с монадой 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 .

Отказ от ответственности: вышеупомянутое было извлечено и запущено из версии Scala в основной ветке, после 2.10.0, так что могут быть различия. Мне, к сожалению, не хватает чистой среды 2.10.0 или 2.10.1, чтобы проверить это.

...