繁体   English   中英

Scala和Jython中的中缀运算符

[英]Infix operators in Scala and Jython

embedded scripting language for end users. 我正在为面向计算的应用评估语言,该应用需要最终用户使用嵌入式脚本语言。 我一直在考虑使用Scala作为主要的基础语言,使用Jython作为脚本接口。 Scala的吸引力在于,我可以定义诸如:*方法,用于矩阵对象的元素乘法,并将其与infix语法a :* b 但是:*在Python中不是有效的方法名称。 Jython如何处理?

由于其灵活性,我会考虑将Scala用作脚本语言。 但是即使使用类型推断,所有valvar以及所需的类型定义对于习惯于使用诸如matlab之类的动态语言的非专业用户来说也太多了。 相比之下,Boo具有选项-ducky选项,该选项可能会起作用,但是我想保留在JVM而不是.NET上。 我认为Scala没有-ducky

更一般地,请考虑以下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之类的基本脚本语言?

思想表示赞赏。

我个人认为您夸大了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))

在这种情况下,除了定义GamVecNorMV等,并创建一个从SymbolIntDouble的隐式定义外,几乎什么都没做,要从一个表中读取,稍后您将在其中存储这些定义(例如使用相当于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)) 
)

在这种情况下,需要对GamMult等进行定义,以处理传递给它们的符号。 但是,多余的“'”绝对令人讨厌。

这不像HBC没有它自己的特质,例如偶尔需要类型声明,在索引之前加下划线,偶尔需要用“ \\in ”替换“ ~ ”,甚至是需要在后面加反斜杠的地方。 只要使用它代替HBC,MathLab或其他人习惯的方法能带来真正的好处,他们就会为自己带来麻烦。

编辑:

阅读所有讨论之后,最好的方法可能是定义DSL的语法,然后使用内置的scala解析实用程序对其进行解析。

我不确定您要达到的目标。 您的脚本语言会是“什么”还是“如何”类型? 您给我的示例是“什么”类型的DSL->您描述了您要实现的目标,而不关心实现。 这些是最能描述问题的语言,按照您要为其构建应用的领域,我认为这是最好的方法。 用户仅以问题域非常熟悉的语法描述问题,应用程序将解析此描述并将其用作输入,以运行模拟。 为此,构建语法并使用scala解析实用程序进行解析可能是最好的方法(您只想向用户公开一小部分功能)。

如果需要“如何”脚本,那么使用已建立的脚本语言是可行的方法(除非您想自己实现循环,基本数据结构等)。

在设计系统时,总是需要权衡取舍。 这里是介于您要向用户公开的功能数量和脚本的简洁性之间。 就我自己而言,我将尽可能少地暴露功能以完成工作,并以“如何”方式完成它-如果模拟给出,用户不需要知道如何模拟其问题更正结果并在合理的时间内运行。

如果向用户公开完整的脚本语言,则DSL只是该脚本语言中的一个小型API,用户将必须学习完整的语言才能使用其全部功能。 并且您可能不希望用户使用其全部功能(这可能会破坏您的应用程序!)。 当您的应用程序不需要连接到Internet时,为什么要公开例如TCP套接字支持? 这可能是一个安全漏洞。

--以下部分讨论了可能的脚本语言。 我上面的答案建议不要使用它们,但是为了完整起见,我离开了讨论。

我没有经验,但是可以看一下Groovy 它是JVM的一种动态类型的脚本语言(由于invokedynamic ,JVM的支持在JDK 7中可能会变得更好)。 它还对操作员重载编写DSL提供良好的支持。 不幸的是,它不支持用户定义的运算符,至少据我所知。

我仍然会使用scala(部分是因为我喜欢静态类型,并且发现其类型推断很好:)。 它的脚本支持非常好,您几乎可以使任何看起来像本地语言的支持(例如,看看它的actors库!)。 它还对函数式编程提供了很好的支持,可以使脚本非常简短。 作为好处,您将可以使用Java库的所有功能。

为了使用scala作为脚本语言,只需将脚本放入以.scala结尾的文件中,然后运行scala filename.scala 有关将Scala与JRuby进行比较的讨论,请参见Scala作为脚本语言

JVM脚本语言中没有明显的可疑对象-JavaScript Rhino,JRuby,Jython和Groovy-不支持用户定义的运算符(您可能需要)。 范也没有。

您可以尝试将JRuby与superators gem一起使用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM