Инфиксные операторы в Scala и Jython - PullRequest
4 голосов
/ 19 августа 2009

Я оцениваю языки для вычислительно-ориентированного приложения, которому нужен конечный пользователь: easy встроенный язык сценариев. Я думал об использовании Scala в качестве основного языка и Jython для интерфейса сценариев. Привлекательность Scala заключается в том, что я могу определять такие методы, как :* для поэлементного умножения матричного объекта, и использовать его с инфиксным синтаксисом a :* b. Но: * не является допустимым именем метода в Python. Как Jython справляется с этим?

Я бы хотел использовать Scala в качестве языка сценариев из-за его гибкости. Но даже с выводом типа все определения val и var и требуемые типы - это слишком много для непрофессионалов, привыкших к динамическому языку, подобному matlab. Для сравнения, у Boo есть опция -ducky, которая может сработать, но я бы хотел остаться на JVM, а не на .NET. Я предполагаю, что нет -ducky для Scala.

В более общем случае рассмотрим следующий DSL (от http://www.cs.utah.edu/~hal/HBC/) для моделирования скрытого распределения Дирихле:

model {
      alpha     ~ Gam(0.1,1)
      eta       ~ Gam(0.1,1)
      beta_{k}  ~ DirSym(eta, V)           , k \in [1,K]
      theta_{d} ~ DirSym(alpha, K)         , d \in [1,D]
      z_{d,n}   ~ Mult(theta_{d})          , d \in [1,D] , n \in [1,N_{d}]
      w_{d,n}   ~ Mult(beta_{z_{d,n}})     , d \in [1,D] , n \in [1,N_{d}]
}

result = model.simulate(1000)

Этот синтаксис потрясающий (по сравнению, например, с PyMCMC) для пользователей, знакомых с иерархическим байесовским моделированием. Есть ли какой-нибудь язык в JVM, который позволил бы легко определить такой синтаксис, наряду с доступом к базовому языку сценариев, например, python?

Мысли приветствуются.

Ответы [ 3 ]

2 голосов
/ 19 августа 2009

Лично я думаю, что вы преувеличиваете издержки Scala. Например, это:

alpha     ~ Gam(10,10)
mu_{k}    ~ NorMV(vec(0.0,1,dim), 1, dim)     , k \in [1,K]
si2       ~ IG(10,10)
pi        ~ DirSym(alpha, K)
z_{n}     ~ Mult(pi)                          , n \in [1,N]
x_{n}     ~ NorMV(mu_{z_{n}}, si2, dim)       , n \in [1,N]

можно записать как

def alpha =                   Gam(10, 10)
def mu    = 1 to 'K map (k => NorMV(Vec(0.0, 1, dim), 1, dim)
def si2   =                   IG(10, 10)
def pi    =                   DirSym(alpha, 'K)
def z     = 1 to 'N map (n => Mult(pi))
def x     = 1 to 'N map (n => NormMV(mu(z(n)), si2, dim))

В этом конкретном случае почти ничего не было сделано, кроме определения Gam, Vec, NorMV и т. Д., И создания неявного определения от Symbol до Int или Double, считывающего таблица, в которой вы будете хранить такие определения позже (например, с эквивалентом loadM). Такие неявные определения будут выглядеть так:

import scala.reflect.Manifest
val unknowns = scala.collection.mutable.HashMap[Symbol,(Manifest[_], Any)]()
implicit def getInt(s: Symbol)(implicit m: Manifest[Int]): Int = unknowns.get(s) match {
  case Some((`m`, x)) => x.asInstanceOf[Int]
  case _ => error("Undefined unknown "+s)
}
// similarly to getInt for any other desired type

Это тоже можно записать так:

Model (
  'alpha    -> Gam(10, 10),
  'mu -> 'n -> NorMV(Vec(0.0, 1, dim), 1, dim)      With ('k in (1 to 'K)),
  'si2      -> IG(10, 10),
  'pi       -> DirSym('alpha, 'K),
  'z -> 'n  -> Mult('pi)                            With ('n in (1 to 'N)),
  'x -> 'n  -> NorMV('mu of ('z of 'n), 'si2, dim)) With ('n in (1 to 'N)) 
)

В этом случае Gam, Mult и т. Д. Должны быть определены несколько иначе, чтобы обрабатывать символы, передаваемые им. Тем не менее, избыток «» определенно раздражает.

Не то чтобы у HBC не было своих собственных особенностей, таких как случайная необходимость в объявлениях типов, подчеркивание перед индексами, случайная необходимость заменить "~" на "\in" или даже обратная косая черта, должен предшествовать позже. Пока есть реальная польза от его использования вместо HBC, MathLab или чего-то еще, к чему привык человек, они будут немного беспокоиться.

0 голосов
/ 20 августа 2009

Ни один из очевидных подозреваемых среди языков сценариев JVM - JavaScript Rhino, JRuby, Jython и Groovy - не имеет поддержки пользовательских операторов (которые вам, вероятно, понадобятся). Ни один не делает Fan.

Вы можете попробовать использовать JRuby с суператорами gem.

0 голосов
/ 19 августа 2009

РЕДАКТИРОВАТЬ:

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

Я не уверен, что вы пытаетесь достичь. Будет ли ваш язык сценариев больше похож на "what" или "how" ? Вы привели мне пример DSL типа «что» -> вы описываете, чего пытаетесь достичь, и не заботитесь о реализации. Это языки, которые лучше всего использовать для описания проблемы, и я думаю, что для домена, для которого вы создаете приложение, это лучший способ. Пользователь просто описывает проблему в синтаксисе, очень знакомом проблемной области, приложение анализирует это описание и использует его в качестве входных данных для запуска моделирования. Для этого, вероятно, лучше всего построить грамматику и выполнить ее синтаксический анализ с помощью утилит разбора scala (вы хотите предоставить пользователям лишь небольшое подмножество функций).

Если вам нужен сценарий «как», то использовать уже установленный язык сценариев - это лучший способ (если вы не хотите самостоятельно реализовывать циклы, базовые структуры данных и т. Д.).

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

Если вы предоставите пользователю полный язык сценариев, ваш DSL будет просто небольшим API на этом языке сценариев, и пользователь должен будет выучить полный язык, чтобы использовать все его возможности. И вы, возможно, не захотите, чтобы пользователь использовал все его возможности (это может нанести ущерб вашему приложению!). Зачем вам, например, предоставлять поддержку сокетов TCP, когда вашему приложению не нужно подключаться к Интернету? Это может быть дыра в безопасности.

-- В следующем разделе рассматриваются возможные языки сценариев. Мой ответ выше не рекомендует их использовать, но я оставил обсуждение для полноты.

У меня нет опыта с этим, но посмотрите на Groovy . Это язык сценариев с динамической типизацией для JVM (поддержка JVM, вероятно, улучшится в JDK 7 из-за invokedynamic). Он также имеет хорошую поддержку для перегрузки операторов и для записи DSL . К сожалению, он не поддерживает определенные пользователем операторы, по крайней мере, насколько мне известно.

Хотя я бы все равно использовал scala (частично потому, что мне нравится статическая типизация, и я считаю, что вывод ее типа хорош :). Его поддержка сценариев довольно хорошая, и вы можете сделать практически все, что угодно, для поддержки родного языка (например, посмотрите на библиотеку актеров!). Он также имеет очень хорошую поддержку для функционального программирования, что делает скрипты очень короткими и лаконичными. И в качестве преимущества вы будете иметь в своем распоряжении все возможности библиотек Java.

Чтобы использовать scala в качестве языка сценариев, просто поместите ваш сценарий в файл, заканчивающийся .scala, а затем запустите scala filename.scala. См. Scala как язык сценариев для обсуждения, сравнивающего scala с JRuby.

...