Loading [MathJax]/jax/output/CommonHTML/jax.js

2012年8月29日水曜日

Scala Tips / Scala 2.10味見 - Interpolation

Scala 2.10.0もMilestone 7がリリースされ、そろそろ仕上がってきた感じです。そこで、ぼちぼち味見を始めることにしました。

ボク的にはScalaの内部DSL機能を強化する言語機能と並列プログラミングに興味があります。そういう意味で2.10では以下の機能をチェックしてみたいと考えています。

また2.8でexperimentalで入ったはずの限定継続の現状も興味があるところです。

Interpolation

Interpolationはざっくりいうと文字列の中にScalaプログラムを埋め込んで評価結果を文字列として取り出すことができる機能のようです。

典型的な使い方が以下になります。文字列の前に「s」をつけると「ScalaScala1c」の形式も可能です。2文字以上になると「${expr}」の形式になります。

  1. def interpolations {  
  2.   val h = "Hello"  
  3.   val w = "World"  
  4.   val s = s"h,w"  
  5.   println(s)  
  6. }  

実行結果は以下になります。

scala> interpolations
Hello, World
format

Interpolationでは文字列の前に指定する識別子で振舞いを変えることができます。前述の「s」は単純に文字列を埋め込むものでしたが、それ以外に識別子「f」が用意されています。

識別子「f」を指定するとjava.util.Formatterの文法に従って埋め込む文字列を整形します。

使用例は以下になります。

  1. def interpolationf {  
  2.   val label = "total"  
  3.   val number = 1234567.89  
  4.   val s = f"label:{number}%,3.1f"  
  5.   println(s)  
  6. }  

実行結果は以下になります。

scala> interpolationf
total: 1,234,567.9

DSL

Interpolationも、識別子「s」と「f」が提供されるだけであれば、便利機能の提供というレベルのインパクトですが、なんと識別子をアプリケーションで自由に追加することができます。この機能を用いればDSLにも利用できそうです。

まず、DSLの受け側としてケースクラスDslを用意します。

Interpolationに新しい識別子dslを追加するためにはStringContextに拡張メソッドdslを追加する必要があります。この目的でこれもScala 2.10で追加されたimplicit classesとしてDslStringContextを定義しました。

  1. case class Dsl(strings: Seq[String])  
  2.   
  3. object Dsls {  
  4.   implicit class DslStringContext(self: StringContext) {  
  5.     def dsl(args: Any*): Dsl = {  
  6.       val a = self.parts.map(Some(_)).zipAll(args.map(_.toString).map(Some(_)), None, None)  
  7.       val b = a.flatMap(x => Seq(x._1, x._2)).flatten  
  8.       Dsl(b)  
  9.     }  
  10.   }  
  11. }  

これを使って新しい識別子dslを用いると以下になります。

  1. def interpolationdsl {  
  2.   import Dsls._  
  3.   
  4.   val table = "MyTable"  
  5.   val cond = "x > 100"  
  6.   val d = dsl"select * from tablewhere{cond}"  
  7.   println(d)  
  8. }  

実行結果は以下のとおりです。

scala> interpolationdsl
Dsl(ArrayBuffer(select * from , MyTable,  where , x > 100, ))

Stringをinterpolation(改竄)した結果は必ずしもStringである必要はないようです。この場合はケースクラスDslを生成して返すことができました。

この例ではDSLを記述する文字列としてSQLを用いてみました。これは任意のDSLを文字列としてScalaプログラムに埋め込むことを狙っていますが、良い感触を得ることができました。

この結果、Scalaをホスト言語とする内部DSLと、Interpolationで記述した外部DSLをシームレスに接続する道筋が見えてきました。

Interpolationを普通に使うとプログラムの実行時にDSLの文法チェックを行うことになりますが、マクロと組み合わせることでコンパイル時の文法チェックも可能になると思われます。

Interpolation(+マクロ)はDSLの実現方式に大きなインパクトがありそうですね。

諸元

  • Scala 2.10.0-M7

0 件のコメント:

コメントを投稿