Home > Scala > Scala : 交互式应用程序,函数组合

Scala : 交互式应用程序,函数组合

函数和交互式应用程序

回调(callback)在交互式应用程序中是很常见的。例如一个按钮被点击,并进行一个特定的动作。在Web 应用程序中创建回调是尤其困难的,除非你拥有像Scala这样强大的工具。下面创建一个方法,它生成一个随机的String,以作为一个全局唯一的标识符(GUID)。

scala> def randomName() = "I"+ scala.util.Random.nextLong.abs
randomName: ()java.lang.String

然后定义一个通用的JavaScript trait, 我们不需要刷新它,假设它包含可以在浏览器中运行的JavaScript 命令。

scala> trait JavaScript
defined trait JavaScript

下面用一个能生成 JavaScript的函数来创建一个Map 以关联GUID:

scala> var callbacks: Map[String, () => JavaScript] = Map()
callbacks: Map[String,() => JavaScript] = Map()
scala> def register(f: () => JavaScript) = {
| val name = randomName
| callbacks += name -> f
| <button onclick={"invokeServerCall("""+name+""")"}>ClickMe</button>
| }
register: (f: () => JavaScript)scala.xml.Elem

当用户点击按钮时,会用 GUID 创建一个Ajax HTTP 请求,Servlet 在map中查找GUID,如果GUID存在,这个函数就会被调用并将JavaScript则返回给浏览器,这个功能的代码类型于:

Scala> def handleAjax(guid: String): HttpResponse =
functionMap.get(guid).map(f => f()) match {
case Some(javaScript) => JavaScriptResponse(javaScript)
case _ => Http404Response()
}

上面的代码是 Lift 框架的简化版本,可以看到,这种写法可以让程序员更关注于业务逻辑。

构建新的函数

我们能以其它函数为基础构建新的函数,函数组合提供了很强大的功能(例如parser combinator),现在来看一下解析一系列的命令和编译一个解析它们的函数的区别。

首先,定义一个語法,在这个語法中,表达式可以是常量值或命名变量。表达式可以加或者乘其它表达式。

下面是描述这个語法的case classes:

sealed trait Expr
case class Add(left: Expr, right: Expr) extends Expr
case class Mul(left: Expr, right: Expr) extends Expr
case class Val(value: Int) extends Expr
case class Var(name: String) extends Expr

解析表达式:

scala> def calc(expr: Expr, vars: Map[String, Int]): Int = expr match {
|   case Add(left, right) => calc(left, vars) + calc(right, vars)
|   case Mul(left, right) => calc(left, vars) * calc(right, vars)
|   case Val(v) => v
|   case Var(name) => vars(name)
| }
calc: (expr: Expr,vars: Map[String,Int])Int

在这里,expr是要计算的表达式,而vars则是一个包含了我们的变量的Map。下面将这个方法调用转化为一个函数:

scala> def buildCalc(expr: Expr): Map[String, Int] => Int = expr match {
|   case Add(left, right) =>
|     val lf = buildCalc(left)
|     val rf = buildCalc(right)
|     m => lf(m) + rf(m)
|   case Mul(left, right) =>
|     val lf = buildCalc(left)
|     val rf = buildCalc(right)
|     m => lf(m) * rf(m)
|   case Val(v) => m => v
|   case Var(name) => m => m(name)
| }
buildCalc: (expr: Expr)(Map[String,Int]) => Int

buildCalc方法返回一个函数,它能传递给其它函数。JVM能够优化这个组合函数,比解析的版本性能更好,这是因为组合函数没有多余的元素与模式匹配相关联。函数是通过不断调用函数的apply方法来计算的,因此,每个节点的代价是一或两个方法的分发而不是整个模式匹配。

Related posts:

  1. Scala 集合框架:List
  2. Scala : Option 和 foldLeft
  3. Scala : Partial Functions 和 Type Parameters
  4. Scala : Functions and Parameters
  5. Scala : 作用域中的变量,容器
Categories: Scala Tags:
  1. No comments yet.
  1. No trackbacks yet.