2012年1月31日火曜日

Scala Tips / Option (4)

Optionから値を取り出すイディオムです。
前回は、Optionに値が格納されているケースといないケースの両方に対応するイディオムでした。今回は、これを拡張してOptionに格納されている値が行おうとしている処理に対して無効だったケースを追加します。
前回の演算は以下の表の示す演算でしたが、これを拡張して:
条件結果
Option[A]がSome[A]Some[B]
Option[A]がNoneNone
以下の表が示す演算にします。
条件結果
Option[A]に有効な値が入っているSome[B]
Option[A]に無効な値が入っているNone
Option[A]がNoneNone
「Option[A]に無効な値が入っている」のケースが加わっています。
以下では、引き続きOption[Int]からOption[String]への変換を例に考えてみます。ただし、Intは0以上のものが有効という条件を追加します。
Optionに入っているIntが0以上の場合、Some[String]が処理結果となります。一方、0未満の場合は無効となりNoneが処理結果となります。
(分類の基準)

Java風

if式でOption#isDefinedを使ってOptionが有効であることを確認後、さらにif式で値が0以上であることを判定します。このプログラムにあるように a.get を二度行なうか、a.get の値を変数に覚えておかなくてはいけません。
def f(a: Option[Int]): Option[String] = {
  if (a.isDefined) {
    if (a.get >= 0) Some(a.get.toString)
    else None
  } else {
    None
  }
}

Scala風

match式を使うと以下のようになります。a.get の二回判定(または a.get の値を変数に記憶)が必要なくなるのでその点はすっきりしています。とはいえ「Noneの場合はNone」の処理を記述するのはScala的には悔しい感じ。
def f(a: Option[Int]): Option[String] = {
  a match {
    case Some(b) => if (b >= 0) Some(b.toString) else None
    case None => None
  }
}

Scala

Scala的なコーディングでは、withFilterメソッドを使って、「0以上」という条件に合わない値の場合に、Some[A]からNoneへの切替えを行います。
def f(a: Option[Int]): Option[String] = {
  a.withFilter(_ >= 0).map(_.toString)
}

Scalaz

Scalaz流のエレガントな書き方はないと思います。

ノート

前回は以下の表の演算を行いましたが、今回はこれを拡張して:
条件結果
Option[A]がSomeSome[B]
Option[A]がNoneNone
以下の表の演算を行いました。
条件結果
Option[A]に有効な値が入っているSome[B]
Option[A]に無効な値が入っているNone
Option[A]がNoneNone
「Option[A]に無効な値が入っている」のケースが加わっていますが、この追加が何を意味しているのかというと、成功の文脈だったものをアプリケーションの意思で失敗の文脈に変えることができるということです。
mapメソッドを使うと、成功の文脈における演算を記述することができましたが、成功の文脈を失敗の文脈に切り替えることはできませんでした。
withFilterメソッドは、指定した条件が真の場合はSome[A]を返し、偽の場合はNoneを返します。また、Noneを受け取った場合はそのままNoneを返します。つまりwithFilterメソッドを使うことで、成功の文脈を失敗の文脈に切り替えることができるわけです。
withFilterメソッドは以下の表の演算を行います。
条件結果
Option[A]に有効な値が入っているSome[A]
Option[A]に無効な値が入っているNone
Option[A]がNoneNone
また、mapメソッドは以下の表の演算を行います。
条件結果
Option[A]がSome[A]Some[B]
Option[A]がNoneNone
この2つの表を連結すると以下の表になります。
条件結果
Option[A]に有効な値が入っているSome[B]
Option[A]に無効な値が入っているNone
Option[A]がNoneNone
以上のようにwithFilterメソッドとmapメソッド連結することで、全体として期待した結果が得られます。
withFilterとfilter
withFilterメソッドとほぼ同じ機能を持つfilterメソッドを使っても同じ結果が得られます。
filterメソッドとwithFilterメソッドは、指定された条件でOptionの値をフィルタリングして、条件に合わない場合は成功の文脈(Some[A])から失敗の文脈(None)に切り替える点は同じです。
異なるのは、filterメソッドはOption[A]を返すのに対して、withFilterメソッドはWithFilterというオブジェクトを返す点です。WithFilterオブジェクトは、mapメソッドなどつないでいく場合に利用するオブジェクトです。
filterメソッドはメソッドチェインの最後に位置する場合に用いるのに対して、withFilterメソッドはメソッドチェインの内部にあり後続に別のメソッドがつながれる場合に使用します。メソッドチェインの最後に位置する場合は、Option[A]のオブジェクトを生成してこれを返すことになりますが、その後にすぐにmapメソッドなどがつながれる場合は、このOption[A]の生成が無駄になります。このような無駄を省くために用意されているのがwithFilterメソッドです。
filterメソッドとwithFilterメソッドの使い分けがよく分からない場合は、filterメソッドを使っておくと安全です。ただし、若干ですが性能的に不利になります。
filterメソッドとwithFilterメソッドには以上のような機能差があるため、Optionの値をフィルタした後にmapメソッドなどをつないでいく場合は、filterメソッドより高速に動作するwithFilterメソッドを使用するのがテクニックになっています。このためイディオムではwithFilterメソッドを採用しました。
collectメソッドとflatMapメソッド
Optionでは、filter/withFilterと同じような使い方ができるメソッドとしてcollect、filterNotが提供されています。
filterNotメソッドはfilterメソッドと条件式が反対に作用するものです。
collectメソッドは部分関数を用いて、Optionの値を変換しながら、成功の文脈と失敗の文脈の切り替えもできるという優れもののメソッドです。
また、今回のイディオムはより汎用性の高いメソッドであるflatMapを用いて実現することもできます。
collectメソッドとflatMapメソッドを使ったイディオムについて、続けて取り上げていきます。

諸元

  • Scala 2.9.1
  • Scalaz 6.0.3

2012年1月30日月曜日

SmartDox 0.2.1 / クラス図の生成埋込み

SmartDox 0.2.1をリリースしました。
SimpleModelerを使って、CSVからクラス図の画像生成と埋込みができるようになりました。

機能

SmartDox 0.2.1では以下のオプションを提供しています。
オプション機能
-html5HTML5生成(試験的)
-html4HTML4生成
-html3HTML3生成
-plainプレインテキスト生成
-pdfPDF生成
-latexLaTeX生成
-bloggerBlogger用のHTML生成
基本的にSmartDox 0.2と同じです。
CSVで記述した情報からクラス図の画像を生成して、文書内に埋め込む機能をサポートしました。

サンプル

SmartDox 0.2.1では以下のようなorg-mode文書が扱えます。
#+TITLE: simplemodeler

* SimpleModelerによるクラス図記述

SimpleModelerを使ってCSVでクラス図を
書くことができます。

#+begin_sm_csv images/sm_csv_simplemodel.png
#actor
顧客
個人顧客,,,,,顧客
法人顧客,,,,,顧客
#resource
商品,商品名,,商品区分(第1類;第2類;第3類)
#event
購入する,,顧客;商品
#+end_sm_csv
#+begin_sm_csv images/sm_csv_simplemodel.png で始まるところがCSV言語で記述したクラス図情報です。この記述から自動的にクラス図の画像(png)を生成して文書に埋め込みます。
この文章中にあるCSVからSmartDoxが(SimpleModeler経由で)生成するクラス図画像は以下のものです。

クラス図情報を記述するCSVの文法は次回に説明します。

PDF

クラス図画像の生成はHTMLやプレインテキストの生成時にも行いますが、ここではPDFを例にして生成されたクラス図画像がどのように文書中に埋め込まれるのかをみてみましょう。
PDFの生成は以下のようにして行います。
$ dox -plain sample.dox
2ページのPDFが生成されます。1ページ目はタイトルと目次ですが、2ページ目に以下のように生成されたクラス図が本文に埋め込まれています。

インストール

プログラムの配布は、Scalaで最近注目されているconscriptを使っています。conscriptのインストール方法は以下のページに詳しいです。
Linux, Macであれば、以下のようにすればインストール完了です。
$ curl https://raw.github.com/n8han/conscript/master/setup.sh | sh
conscriptをインストールした後、以下のようにしてSmartDoxをインストールします。
$ cs asami/dox
以下の2つのコマンドがインストールされます。
dox
SmartDoxコマンド
sdoc
SmartDocコマンド(互換用)
依存プロダクト
SmartDoxでは、以下のプロダクトに依存しています。
プロダクト使用する機能
LaTeXPDF生成
Graphviz画像生成
Ditaa画像生成
プロダクトに依存する機能を使わない場合は必要ありません。
LaTeX
platexコマンドとdvipdfmxコマンドが実行可能になっていれば基本的にはOKです。
Mac OS上でmacportsを使ってインストールしたLaTeXで動作確認しています。他の環境の場合、スタイルファイルなどがない可能性があります。
Graphviz
dotコマンドが実行可能になっていればOKです。
Mac OS上でmacportsを使ってインストールしたGraphvizで動作確認しています。
Ditaa
ditaaコマンドが実行可能になっているか、optlocalsharejavaditaa09.jarのJarファイルが存在していればOKです。
Mac OS上でmacportsを使ってDitaaをインストールすると、optlocalsharejavaditaa09.jarに配置されます。このditaa09.jarを決め打ちで使用しています。(いずれパラメタで指定可能にする予定です。)
それ以外の環境では、シェルスクリプトなどでditaaコマンド(インストールされているJarファイルを呼び出す)を作成してください。

使い方

まだマニュアルがないので、文書フォーマットは org-modeを参考にしてください。あまり難しい文法を使わなければ大体大丈夫だと思います。
org-mode形式で作成した文書から以下のようにしてHTMLやPDFに変換してください。
$ dox -html4 mydoc.dox
$ dox -pdf mydoc.dox

2012年1月27日金曜日

Scala Tips / Option (3)

Optionから値を取り出すイディオムです。

Optionの値を取り出すのは、Option#getメソッドを使うかパターンマッチングでSome(x)とするのが普通ですが、イディオムとして整理する場合は、適材適所という切り口が重要になるので、もう少し大きな粒度のシーケンスでまとめておきたいところです。

Optionから値を取り出す処理は以下の2つのコーディングパターンのいずれかの構成要素として使われることが多いでしょう。それぞれのケースについて考えていきます。

  • Option[A]からOption[B]に変換
  • Option[A]からBに変換

まず、「Option[A]からOption[B]に変換」のイディオムです。Option[A]からOption[B]に変換するケースで注意が必要なのは、Option[A]がSome[A]ではなくNoneだったケースです。この場合は、AからBへの変換処理は行わずNoneにしなければなりません。これを表にまとめると以下のものになります。

条件結果
Option[A]がSome[A]Some[B]
Option[A]がNoneNone

Optionから値を取るイディオムでは、Noneのケースも包含した形にしておく必要があるというわけです。

以下では、Option[Int]からOption[String]への変換を例に考えてみます。

(分類の基準)

Java風

if式でOption#isDefinedを使って値の有無を判定します。Option#isDefinedとOption#getが泣き別れになるので、あまりよい感触ではありません。

def f(a: Option[Int]): Option[String] = {
  if (a.isDefined) Some(a.get.toString)
  else None
}

Scala風

match式を使うと以下のようになります。こちらの方が綺麗ですね。

def f(a: Option[Int]): Option[String] = {
  a match {
    case Some(b) => Some(b.toString)
    case None => None
  }
}

Scala

Optionの処理にmapメソッドを使うのがScala的なコーディング。mapメソッド内に処理を記述します。(処理を行う関数を引数に指定します。)Noneの場合にはNoneになる、という処理はmapメソッド内で自動的に行ってくれるのがミソです。

def f(a: Option[Int]): Option[String] = {
  a.map(_.toString)
}

Scalaz

Scalaz流のエレガントな書き方はないと思います。

ノート

Optionの心は「成功/失敗の計算文脈」にあります。成功または失敗の状況を文脈として持ちまわるモナドという意味です。ボクが現時点で理解しているOptionの意味ですが、この言葉にピンと来ない場合もあまり気にする必要はありません。

実用的には、この抽象的な概念が具体的にどう役に立つのかという点が重要です。具体的に役に立つコーディングパターン、すなわちイディオムを洗いだしてマスターしておけばよいでしょう。

「成功/失敗の計算文脈」が具体的に何を指すのかという点について、前述した以下のmapメソッドを例に考えてみましょう。

def f(a: Option[Int]): Option[String] = {
  a.map(_.toString)
}

Option#mapメソッドは関数を引数に取りますが、成功の文脈(すなわちSome[Int]の場合)では関数を実行した結果(String)を再度Someに詰め直したもの(Some[String])を返却値とします。Someに詰め直すということは値を更新しつつ、成功の文脈を引き継ぐということです。

一方、失敗の文脈(すなわちNoneの場合)は何もせず自動的にNoneを返却値とします。つまり、失敗の文脈の処理についてはプログラマは直接指定する必要はなく、Option側で自動的に行ってくれるということです。失敗の文脈が自動的に引き継がれる点は、Java風(if式を使う場合)やScala風(match式を使う場合)と比べてみると違いが明確です。

プログラマの関心が低い方の文脈である失敗の文脈が、Optionが内包しているロジックにより自動的に引き継がれるのがOptionの旨みで、Optionの実現技術であるモナドの威力です。

2012年1月26日木曜日

「ソーシャルメディアマーケティングの基本戦略」のマインドマップとクラス図

1月21日(土)に横浜モデリング勉強会を行いました。また、会場には(株)アットウェア様の会議室をお借りしました。参加された皆さん、アットウェア様、どうもありがとうございました。懇親会では、勉強会でモデル駆動開発のハンズオンみたいなこともどうか、という意見もありました。そちらの方向への展開も考えてみたいと思います。
この勉強会で、浅海が作成したモデルを紹介します。モデルはMindmapModelingの手法で作成しました。(勉強会で使用したチュートリアル)
モデリングの対象は、IT media エンタープライズ ビジネスイノベーション誌に掲載された小川浩氏の記事「ソーシャルメディアマーケティングの基本戦略 」です。前回、前々回は経済ネタだったのですが、今回はITエンジニアにも親和性の高いソーシャルメディアのマーケッティングをテーマにしてみました。

単語を抜き出す

まず、最初の作業で記事中から単語を抜き出します。単語を抜き出しながら、登場人物、道具、出来事を中心にMindmapModelingの定めた分類に従って仕分けしていきます。
この結果、できた最初のマインドマップが以下のものです。(以下、図をクリックすると拡大します。)

記事の内容がソーシャルメディアマーケッティングの構造についてなので、そのあたりに単語が集中しています。

関係の洗練

次の段階では、抽出した、登場人物、道具、出来事の洗練を行います。用語の名寄せ、用語の種類(generalization)や部品構成(aggregation)を整理していきます。また、この段階で区分(powertype)の抽出を開始します。
以上の作業を行った結果のマインドマップは以下のものです。

SimpleModelerのサービスを使用して作成したクラス図は以下のものになります。

今回は、ソーシャルメディアマーケッティングについての区分を整理を中心に作業しました。自然言語の文章としては意味が通っても、モデルの用語としては曖昧なところが出てくるのでそういった点を補ったり、MECE(Mutually Exclusive and Collectivily Exhausitive、もれなくだぶりなく)を念頭に区分の中身を整理しました。

出来事と物語

次の段階では、対象となる世界の動的な側面を捉える出来事や物語を整理していきます。出来事や物語を洗練していくことによって、出来事や物語における登場人物や道具の役割が明確化され、より登場人物や道具の構造をさらに洗練させることができます。出来事や物語で抽出した役割は、役割(role)としてモデル化して「役割」構造枝に配置し、役割の持つ構造を洗練していきます。

SimpleModelerのサービスを使用して作成したクラス図は以下のものになります。

今回は、よい物語が思い浮かばなかったので、出来事と規則を中心に洗練を進めました。
また、ソーシャルメディアマーケッティングの手法として、記事中で明示的に列挙してあった(1)ペイパーポスト、(2)クチコミを分析、(3)情報発信だけでなく、記事中の他の場所にばらばらに書いてあった(4)コールセンター、(5)対面販売、(6)イベント応募も加えています。
このように著者が形式知として明示したものにも案外抜けがあるものです。これを記事中から拾い集めてきて形式知化し、情報の再構成を行うのがMindmapModelingの目的です。
以上が勉強会での作業です。

仕上げ

最後にドメインモデルの形に仕上げることにしましょう。SimpleModelerを使用して作成したクラス図を見ながら調整していきます。
ついでなのでSimpleModelerの機能を拡張して、より適切なクラス図が表示されるようにしてみました。来週ぐらいにSimpleModelerのサービスを新しいバージョンのSimpleModelerにアップグレードしたいと思います。
以上の作業で作成したマインドマップとクラス図は以下のものになります。


かなりドメインモデルとして整理されました。ドメインモデルがこのレベルの情報を持つようになると、クラス図ベースでモデルの推敲をはじめても大丈夫です。
生成されたクラス図をみてみると、たとえば「市場シェアが二番手、三番手の企業が大域的な市場シェアを奪うためにソーシャルマーケティングを行う」という物語(Business UseCase)を作成し、この物語を軸にモデルの精度をあげると面白いのではないか、とか色々とイメージが湧いてきますね。
初見のモデリングでは、推敲のベースとなる初期モデルを作るのがなかなか大変なので、MindmapModeling→クラス図のアプローチはなかなか有力ではないかと思います。

2012年1月25日水曜日

Scala Tips / null

null値の可能性がある値をnull値ではない普通の値に持ち上げるイディオムです。

(分類の基準)

Java風

if式で変数がnullかどうかを判定します。

def f(a: String, b: String): String = {
  if (a == null) b
  else a
}

実際に使う時は以下のような感じになります。

val c = if (a == null) b else a

Scala風

match式を使う時は以下のようになります。この場合は、Java風の方が簡潔ですね。

def f(a: String, b: String): String = {
  a match {
    case null => b
    case _ => a
  }
}

Scala

OptionとOption#getOrElseを使うと簡潔に記述できます。

def f(a: String, b: String): String = {
  Option(a) getOrElse b
}

Scalaz

Scalazを使うと、さらに簡潔に記述することができます。

def f(a: String, b: String): String = {
  a ?? b
}

以下のような形でメソッドの引数に書きたい場合は、"??"を使った簡潔な記述方法は重宝します。

val a = SomeJavaObject.getStringValue()
println("Value is " + a ?? "unknown")

ノート

プログラムの実行速度という観点では、「Java風」が一番速く、「Scala」はオブジェクト生成とメソッド呼出しが余分に発生するためかなり遅くなります。「Scalaz」は、さらに一段余分にオブジェクト生成とメソッド呼出しが発生するため、さらに低速です。

つまり、Javaの実行速度とScalaの記述力のトレードオフが発生するわけです。実行速度を採るのであればJavaで書けばよいので、Scalaで書く以上、簡潔に記述できることを重視するのがよいでしょう。

まずScalaで書いてみて、プロファイルでホットスポットと判明した処理については、Java風に書き直したり、Java(場合によってはC++)で書いて呼び出すというアプローチになります。

2012年1月24日火曜日

Scala Tips / Option (2)

null値の可能性がある値をOptionに持ち上げるイディオムです。

Scalaでは、できるだけnull値を使わないようにするのが、プログラミングのコツになっています。そのため、既存のJavaプログラムから戻ってきた値などを速やかにOptionに持ち上げる、といった処理がよく出てきます。この処理を簡潔に書けるイディオムを覚えておくとプログラミングがスムーズになります。

(分類の基準)

Java風

if式で変数がnullかどうかを判定します。

def f(a: String): Option[String] = {
  if (a == null) None
  else Some(a)
}

実際に使う時は以下のような感じになります。

val b = if (a == null) None else Some(a)

Scala風

match式を使うこ以下のようになります。この場合は、Java風の方が簡潔ですね。

def f(a: String): Option[String] = {
  a match {
    case null => None
    case _ => Some(a)
  }
}

Scala

Optionオブジェクトに目的にぴったりあうメソッドapplyがあるので、これを使うのがイディオム。Option(a)は、Optionオブジェクトのapplyメソッドを呼び出す簡略記法です。

def f(a: String): Option[String] = {
  Option(a)
}

Optionの持つ基本機能なのでイディオムというのも大げさですが、ボクも長年この使い方を知らずに損なコーディングをしていたので、イディオムとしてまとめておきました。(Scala 2.8でサポートされた機能のようです。)

パッと見は Option(null) とすると Some(null) が返ってきそうですが、None が返って来てくれるということですね。Some(null) が欲しい場合には、文字通り Some(null) とします。

Scalaz

Scalaz流のエレガントな書き方はないと思います。

利用シーン

Scalaでnullを使いたいユースケースとして、メソッドのデフォルト値があります。(いずれイディオムとして取り上げたいと思います。)

case class Person(name: String, address: Option[String])

object Person {
  def apply(name: String, address: String = null) = {
    new Person(name, Option(address))
  }
}

ここを以下のようにしたくないということですね。

new Person(name, if (address == null) None else Some(address))

2012年1月23日月曜日

SmartDox 0.2

SmartDox 0.2をリリースしました。
PDF、プレインテキスト、HTML4の生成をサポートしました。また、GraphvizやDitaaを使った画像の生成と埋込みもできるようになりました。
エラー処理などがまだ柔らかいですが、ある程度使えるレベルのものになってきたと思います。

機能

SmartDox 0.2では以下のオプションを提供しました。
オプション機能
-html5HTML5生成(試験的)
-html4HTML4生成
-html3HTML3生成
-plainプレインテキスト生成
-pdfPDF生成
-latexLaTeX生成
-bloggerBlogger用のHTML生成
html4, html3, plain, pdf, latexはSmartDocのエンジンを使用しています。
html5とbloggerはSmartDoxで新規に開発を進めたものです。
html5は試験的な簡単な実装の段階です。
bloggerは、このブログでも使用しているBloggerでブログを書くときに使用するHTMLを生成します。生成したHTMLをBloggerのHTMLエディタに手動で貼り付けて使用します。前回のエントリから、このbloggerオプションを使用しています。
また、Dot言語(Graphviz)とDitaa言語で記述した画像を生成して、文書内に埋め込む機能をサポートしました。

インストール

プログラムの配布は、Scalaで最近注目されているconscriptを使っています。conscriptのインストール方法は以下のページに詳しいです。
Linux, Macであれば、以下のようにすればインストール完了です。
$ curl https://raw.github.com/n8han/conscript/master/setup.sh | sh
conscriptをインストールした後、以下のようにしてSmartDoxをインストールします。
$ cs asami/dox
以下の2つのコマンドがインストールされます。
dox
SmartDoxコマンド
sdoc
SmartDocコマンド(互換用)
依存プロダクト
SmartDoxでは、以下のプロダクトに依存しています。
プロダクト使用する機能
LaTeXPDF生成
GraphvizDot言語画像生成
DitaaDitaa言語画像生成
プロダクトに依存する機能を使わない場合は必要ありません。
LaTeX
platexコマンドとdvipdfmxコマンドが実行可能になっていれば基本的にはOKです。
Mac OS上でmacportsを使ってインストールしたLaTeXで動作確認しています。他の環境の場合、スタイルファイルなどがない可能性があります。
Graphviz
dotコマンドが実行可能になっていればOKです。
Mac OS上でmacportsを使ってインストールしたGraphvizで動作確認しています。
Ditaa
ditaaコマンドが実行可能になっているか、/opt/local/share/java/ditaa0_9.jarのJarファイルが存在していればOKです。
Mac OS上でmacportsを使ってDitaaをインストールすると、/opt/local/share/java/ditaa0_9.jarに配置されます。このditaa0_9.jarを決め打ちで使用しています。(いずれパラメタで指定可能にする予定です。)
それ以外の環境では、シェルスクリプトなどでditaaコマンド(インストールされているJarファイルを呼び出す)を作成してください。

使い方

まだマニュアルがないので、文書フォーマットは org-modeを参考にしてください。あまり難しい文法を使わなければ大体大丈夫だと思います。
org-mode形式で作成した文書から以下のようにしてHTMLやPDFに変換してください。
$ dox -html4 mydoc.dox
$ dox -pdf mydoc.dox

サンプル

SmartDox 0.2では以下のようなorg-mode文書が扱えます。
#+title: SmartDoxサンプル
#+author: 浅海
#+date: 2012年1月22日

* 文章

これは *SmartDox* の文章です。

- SmartDoxのコンセプトは(org-mode+html5)/2
- HTMLに加えてPDFやプレインテキストを生成することができます。
- GraphvizやDitaaの画像を生成して埋め込むことができます。

* 表

| オプション | 機能                 |
|------------+----------------------|
| -html5     | HTML5生成(試験的)    |
| -html4     | HTML4生成            |
| -html3     | HTML3生成            |
| -plain     | プレインテキスト生成 |
| -pdf       | PDF生成              |
| -latex     | LaTeX生成            |
| -blogger   | Blogger用のHTML生成  |

* 画像

** graphviz

[[http://www.graphviz.org/][Graphviz]] の図を直接書くことができます。

#+begin_dot images/dot_example.png -Tpng
digraph G {
  Hello->World
}
#+end_dot

** ditaa

[[http://ditaa.sourceforge.net/][Ditaa]] の図を直接書くことができます。

#+begin_ditaa images/ditaa_example.png
+--------+   +-------+    +-------+
|        | --+ ditaa +--> |       |
|  Text  |   +-------+    |diagram|
|Document|   |!magic!|    |       |
|     {d}|   |       |    |       |
+---+----+   +-------+    +-------+
    :                         ^
    |       Lots of work      |
    +-------------------------+
#+end_ditaa

「#+begin_dot images/dot_example.png -Tpng」で始まるところがGraphviz言語で記述した画像、「#+begin_ditaa images/ditaa_example.png」で始まるところがDitaa言語で記述した画像です。この記述から自動的に画像(png)を生成して文書に埋め込みます。

PDF

PDFの生成は以下のようにして行います。
$ dox -plain sample.dox
以下の3つのページから構成されるPDFが生成されます。




プレインテキスト 

プレインテキストの生成は以下のようにして行います。
$ dox -plain sample.dox
以下のプレインテキストが生成されます。


2012年1月20日金曜日

Scala Tips/Option

プログラミング言語の習得で重要なことの一つは、局面ごとに使うイディオムを体で覚えて無意識に出てくるようにすることです。

Scalaでのイディオムも少し見えてきたので、少しずつ整理していきたいと思います。

基本文法を覚えたての知識でのコーディングからScalazまでを併置するようにしました。以下のような分類にしています。

Java風
Javaプログラミングの感覚でコーディングしたもの
Scala風
Scalaらしい文法を使っているが、少し泥臭い感じ
Scala
Scalaでのイディオム
Scalaz
Scalazでのイディオム

Java風、Scala風は問題を明確にするための参考情報で、ScalaまたはScalazが推奨の方法です。

今回は、Optionから値を取り出す時に、Noneの場合デフォルト値を使用する方法です。

Java風

if式でOptionのisDefinedメソッドを判定します。安全確実ですが、if式、Option#isDefined、Option#getが出てきたら、Scala的にはちょっと負けっぽい。

Option#isDefinedとOption#getが何かの拍子で泣き別れになるとバグの元になるので、この組合せはできるだけ避けたいわけです。

def f(a: Option[Int]): Int = {
  if (a.isDefined) a.get
  else 0
}

Scala風

match式を使うことで、if式、Option#isDefined、Option#getが見えなくなりました。ただ、やろうとしていることに対して記述がやや冗長な感触です。

def f(a: Option[Int]): Int = {
  a match {
    case Some(b) => b
    case None => 0
  }
}

Scala

Optionに目的にぴったりあうメソッドgetOrElseがあるので、これを使うのがイディオム。事前に用意されているメソッドを使うだけなのでイディオムと呼ぶのはやや大げさですが、ユースケースに対する解を、考えて分かるのではなく、無意識に出てくるのが大事なので、イディオムとして取り上げています。

def f(a: Option[Int]): Int = {
  a getOrElse 0
}

Scalaz

Scalazの場合は"|"でデフォルト値をより簡潔に記述することができます。

def f(a: Option[Int]): Int = {
  a | 0
}

2012年1月11日水曜日

SmartDoxの実装技術

昨日はSmartDoxの紹介をしましたが、 今日はSmartDoxの実装技術について説明します。
既存のプログラムの改良では、今まで積み上げてきたアーキテクチャや 使っているフレームワークの関係があって、 思い切ったコーディング方針の変更はなかなかできません。
SmartDoxは新規開発なので、練習も兼ねて ボクが認識している今風のScalaプログラミングを取り入れてみました。
  • Scala
  • sbt
  • conscript
  • GitHub
  • 関数型プログラミング
  • 代数データ構造
  • Scalaz
  • パーサーコンビネータ

Scala, sbt

実装言語Scala、ビルドツールsbtは現在の既定路線です。
sbtは、後発だけあって何かと使いやすいのと、Scalaプログラミング特有の 色々な事情をハンドリングしてくれるので、Scalaプログラミングでは必須です。
たとえば、Scalaは、コンパイルしたScalaバージョンの異なるライブラリのバイナリ互換が鬼門で、 JavaだとJARファイルが libname-1.0.jarとなるところを、Scalaだとlibname2.9.1-0.1.jarといった具合に 使用するScalaライブラリのバージョン(2.9.1)をファイル名に埋め込むのが、基本的な運用に なっていますが、sbtはこのあたりをうまくハンドリングしてくれます。
編集、デバッグにはEclipseを使っていますが、sbtのEclipseプラグインで「.classpath」を生成して、 ライブラリの依存性を取り込む運用にしています。
ただし、sbtだけでは力不足のところもあります。 以下の処理はsbtでやり方を見つけられなかったのでmavenとantを併用しています。
  • JavaのみのプロジェクトのJar作成(2.9.1を付けないJar名)
  • FTPによるmavenリポジトリへのアップロード(sftpならできるのですが、昔ながらのftpはダメみたい)

conscript

SmartDoxのインストールには conscript を使いました。
conscriptはGitHubに格納したアプリケーションの構成情報を使用して、 アプリケーションの依存関係を解決した上でローカル環境にインストールしてくれる インストーラです。
プログラムの提供側、利用者側のどちらもかなり便利なので、これから広く使われるように なるのではないかと思います。

GitHub

ソースコードの管理はGitHubを使っています。 GitHubはUIが使いやすいので、 このところ新規プログラムはGitHub上で開発していますが、 SmartDoxの場合は、conscriptを使うというためという理由もあります。
GitHubは、ソースコードのバージョン管理という枠組みを超えて、 conscriptのような形でソフトウェアリポジトリ的な使われ方もしてきています。 こういう新しい応用が出てくるので、使っていて刺激的ですね。

関数型プログラミング

関数型プログラミングは、ボクがLispをかじっていた頃(25年ぐらい前)はラムダ計算をベースに、 List、クロージャといった部品を使ってプログラミングしていくものでしたが (さらにいうと綺麗につくると性能がでないので、手続き型的なプログラミングにしたり、 nreverseといった破壊的な関数を使うのがバッドノウハウ)、現在は状況が一変しています。
まず ハードウェア性能の向上で、関数型言語の宿命だった動作性能は事実上あまり問題にならなくなっています。 Javaを使って大丈夫な用途であればScalaでも基本的には大丈夫と考えてよいでしょう。 RubyやPythonで大丈夫な用途であれば、Scalaだと逆に高速に動作しそうです。
技術的には、 モナド、型クラスという新しい技術が登場し、これが新しい関数型プログラミングの基盤になって います。
ボクも2008年にScalaを始める前は、 昔の関数型プログラミングのイメージで関数型言語を捉えていたのですが (List処理が便利で開発効率がアップとか)、 現在では全く別物と考えています。 モナド、型クラスはそれだけのインパクトのある技術ということが分かりました。 いつの間にか、こんなことになっていたのか、という感じです。
さらに、Scalaでは関数型プログラミング(FP)とオブジェクト指向プログラミング(OOP)の融合した Object-Functional Programming(OFP)という概念が提唱しています。
歴史的な蓄積やOOADからの連続性を考えると、 OOPは今後も軸の一つで在り続けることになると予想されます。 ここにFPの記述力をどのように融合させていくのかということが、 実務の世界では非常に重要になるのは明らかで、 OFPはこれは今後大発展する分野と考えています。
このあたりを意識しつつ SmartDoxの開発では、今風のFP的な技術をできるだけ使うことにしました。

代数的データ型

まずデータ構造として、代数的データ型(Algebraic data type)を使用します。 Scalaでは、代数的データ型は直接サポートされていませんが、 case classがこの目的での利用を想定して提供されています。 たとえば A Scala Tutorial for Java programmers にも以下の記述があります。 このあたりの背景は、 Object-Oriented Pattern Matching に詳しいようです。
In Java, such a tree would be represented using an abstract super-class for the trees,
and one concrete sub-class per node or leaf. In a functional programming language,
one would use an algebraic data-type for the same purpose. Scala provides the concept of case classes which is somewhat in between the two
今までは、内部データ構造はオブジェクト指向的な作り方にしていたわけですが、 SmartDoxではcase classを使ってimmutableな構造をにしてみました。
オブジェクト指向的な作りの場合、可変オブジェクトを複数のコンポーネントで共有して 少しづつ変更を加えていくプログラミングモデルになりますが、 代数的データ型(case class&immutable)にすると、コンポーネントで全複写しながら変換する プログラミングモデルになります。 immutableにすると、なにか不測の事態があったときの回避方法が限られるためOOP派的には 非常に怖い選択ですが、 FPでは避けて通れない道です。
SmartDoxでは、このプログラミングモデルにチャレンジしてみたわけです。 今の所、特に問題もなく、このプログラミングモデルでもやっていけそうな感触を得ています。
また、代数的データ構造を取っても、いざという時には型クラスの技法を使って 色々細工ができそうという読みもありました。 なにか問題が出てきたら試してみようと思っています。

Scalaz

Scalaz は、型クラスと純粋関数型データ構造を提供するScalaライブラリです。 Scalaの暗黙型変換、暗黙パラメータの機能を利用してHaskell的な型クラスを提供しています。
Scalaプログラミングを足掛け4年程やってきて分かってきたのは、 FPは関数の合成でプログラミングしていくのがコツということです。 Scalaでも提供されているMonadという仕組みは、この関数合成のメカニズムの一種で 普通の関数合成(composeやandThen, orElseなど)よりもより強力な関数合成を可能に します。 このMonadを活用したプログラミングスタイルをMonadicプログラミングと呼ぶようです。
Scalaの基本機能にもMonadはあるので、ScalaだけでもMonadicプログラミングは できるのですが、Scalazの強力な型クラス群を使用すると、さらに強力な Monadicプログラミングを行うことができるようになります。
Scalazが用意している型クラスはたとえば、Monoid, Functor, Applicative Functor, Monad といったもので、MonadをKleisli圏で合成するようなこともできるようになっています。 このあたりの型クラスを手足のように使えるようになるのが現在目標としていることで、 そのためにSmartDoxではできるだけScalazを使ってプログラミングする方針にしています。
Scalazを使うもう一つの効用は、Scalaで型クラスを使うためのよいお手本になるということ。 Scalaでは、型クラスの機能は直接サポートされておらず、暗黙パラメタ、暗黙変換の機能を駆使 して実装する必要があります。この実装技術をScalazで学ぶことができます。
型クラスは、フレームワークと実装クラスを疎結合に保ちつつ(静的な)多態性を可能にする 非常に強力な言語機能と理解しています。 Scalazの技法を使えば、Scalaでも型クラスを使った プログラミングが可能になるわけで、いずれ自分のプログラミング技法に 取り入れたいと考えています。

パーサーコンビネータ

SmartDoxでは、 SmartDox文書のパースにパーサーコンビネータを使ってみましたが、 驚くほど簡単にパーサーを書くことができることが分かりました。
パーサーの記述はBNF的なDSLになっていますが、基本的な動きとしては MonadicでかつApplicativeという感じです。 Parser[T]を返す関数がMonadic的な動き、その中で「^^」メソッドに渡すクロージャが Applicative的な動きと思います。
簡単なパーサーであれば、BNF的DSLという理解の範囲で使えますが、 細かいことをしようとするとMonadicかつApplicativeな動きを理解して いないと辛そうです。 パーサーコンビネータをある程度使いこなせるようになったのも、 Scalazを使ってMonadicプログラミングに慣れてきた効用かなと 思います。
パーサーコンビネータを使っていて分かったのは、 パーサーコンビネータは文字列以外にも使えるということ。 DOMなどのXML木やマイ代数的データ型からパターンマッチングで構造を抽出して ドメインモデルを構築するという用途には簡単に適用できそうです。 翻って考えてみればこのあたりがMonadicプログラミングの威力ですね。


以上、SmartDoxを素材にScala+Scalazを中心としたFP技術を概観してきました。 15年前はC→Javaによって、OOPがメインストリームのプログラミングパラダイムになり プログラミングの生産性が大きく向上しました。 それと同等の大きなムーブメントがFPの本格導入により起こりそうです。 もちろん前述したように、OOPは今後も軸の一つとなり続けるでしょうから、 OOPとFPを融合した新しいプログラミングパラダイムという形になるでしょう。
最後にどのプログラミング言語が残るのかは分かりませんが、現時点では Scala+Scalazで技を磨いておくのが有力な選択肢だと思います。

2012年1月10日火曜日

SmartDox

年末年始はまとまった時間が取れたこともあって、 以前から構想していた文書処理アプリケーションの SmartDoxを作ってみました。 まだ、実用レベルではないですが一応ミニマムな実装が動いたところです。

SmartDoxは、1998年から作り続けているSmartDocの後継バージョンです。 SmartDoc2という名前でもよかったのですが、smartdox.orgというドメイン名が取れたので SmartDoxにしてみました。 SmartDocの場合、ドメイン名にxmlsmartdoc.orgを使っているのですが、SmartDoxでは「XML」が 必須でなくなるので「XML」の文言のないドメイン名を新しく使うことにしました。

動機

1998年にSmartDocを作る時も、プレインテキストベース(当時だとsetext、今だとSphinxあたりが候補) にするかXMLベースにするかという選択があったのですが、 プレインテキストベースだとパーサーを書くのが大変だったのと、当時のプレインテキストベースの マークアップ言語だと表組みや画像をマークアップする方法がなかったこともあって、XMLを 選択しました。 Emacsのsdoc-mode(sgml-modeを拡張)を使えば、XMLといっても入力、編集は問題ないので、 SmartDocは現在まで使い続けています。

ではなぜSmartDocの新バージョンを作ることにしたのかというと以下の理由があります。

  • org-modeが構造化プレインテキストワープロであることが分かった
  • SimpleModelerで、モデルの仕様記述
  • 自作アプリケーションで文章を扱うときの受け皿
  • Evernoteでの文書編集
  • iPad, iPhoneからの文書編集
org-mode

org-modeは、Emacs上で動作するアウトラインプロセッサです。 アウトラインプロセッサはMindmapModelingとの親和性も高そうなので、 以前からOmni Outlinerやorg-modeを調べていたのですが、 年末にorg-modeを触っていて、実は大変すごいことになっていることが判明しました。 org-modeは、アウトラインプロセッシング機能を持った構造化プレインテキストワープロと呼んでも 差し支えないEmacsアプリケーションだったのです。

特に驚愕したのは以下の機能。

Emacsをメインに使いながら今まで気づかなかったのは不覚でした。

org-modeの威力を目の当たりにし、今まで懸案にしていた色々なミッシングリンクが繋がってきました。 そこで得たインスピレーションをベースにSmartDox開発を開始することにしたわけです。

SimpleModelerで、モデルの仕様記述

SimpleModelerは、テキストDSLでモデルを記述し、このモデルからAppEngineやAndroidの アプリケーション(ドメインモデル+α)を生成するモデルコンパイラです。 SimpleModelerでは、クラス図や状態遷移図/表を含んだ仕様書生成も行いますが、この仕様書で 使用する自然言語による仕様記述の記述方法が懸案事項になっていました。 SmartDocをベースにした記述方式を仮実装していたのですが、これをオーバーホールし、 新規に本格的な文書処理系で実現するのがSmartDoxの目的の一つです。

自作アプリケーションで文章を扱うときの受け皿

SimpleModelerに限らず、自作アプリケーションで文章を扱いたいというニーズは色々あります。 たとえば、ヘルプとして構造を持った長めの文章を表示したいとか、そういう細々した用途です。

この目的で、org-mode文書を操作するScalaコンポーネントを用意しておきたいというのが、 SmartDoxの目的の一つです。 ボクが開発するアプリケーションは goldenport というアプリケーションフレームワーク上に構築していますが、 SmartDoxのコア はgoldenportからも切り離して、より汎用的な部品として使用できるような アーキテクチャにしています。 もちろんgoldenportでもSmartDoxに対応してSmartDoxをアプリケーションに容易に組み込む枠組みを 提供する予定です。

Evernoteでの文書編集

ノートやアイデアの管理にEvernoteを使っていますが、Evernoteのエディタが今ひとつ使いづらいのと、 Evernoteで記録した情報の再利用という目的で、Evernoteのエディタでも使用できる 構造化プレインテキストの導入を考えていました。 この目的にSmartDox文書を使用します。

また、Evernote APIを使ってSmartDox文書を格納したEvernoteノートの操作など、色々と 面白い応用がありそうです。

iPad, iPhoneからの文書編集

最近は iPadやiPhoneからTextforceを用いてDropbox上のテキスト文書を編集する運用を行っています。

PCからはEmacsを使うのでXML系のテキスト文書でも問題はないのですが、 Textforce(のようなプレインなテキストエディタ)でXML文書を編集するのはかなり辛いので、 構造化プレインテキストの導入を考えていました。 Evernoteの場合と同様に、ここもSmartDox文章がぴったりはまりそうです。

コンセプト

SmartDoxのコンセプトは、「(HTML5 + org-mode) / 2」です。 (SmartDocのコンセプトは、「(HTML + LaTeX) / 2」で、これをXML上に構築していました。)

SmartDoxは、HTML5とorg-modeをごちゃまぜにした記述方式にしました。 HTML5のサブセットとorg-modeのサブセットを合体させた文法にしています。 (という予定です。現在はorg-mode上に一部HTML5を取り込んでいます。)

普通の範囲のHTML5文書をHTMLエディタで編集したテキスト、 普通の範囲のorg-mode文書をEmacs上のorg-modeで編集したテキストの両方から HTML、プレインテキスト、LaTeX、PDFを生成します。(という予定です。) また、同一文章にHTML5とorg-modeを混在させ、さらにSmartDox専用の記述方式で 技術文書向けの便利な指定も可能にします。

具体的には、以下のような記述になります。

* SmartDox文書

これは<b>SmartDox</b>文書です。
<!DOCTYPE html>
<html>
<head><title>SmartDox文書</title></head>
<body>
<section><h2>SmartDox文書</h2>
<p>これは*SmartDox*文書です。</p>
</section>
</body>
</html>

org-modeを主体にして、細かい指定が必要なところは HTML5やSmartDox専用記述方式を併用するという運用イメージです。

インストール

プログラムの配布方法は、Scalaで最近注目されているconscriptにしました。 conscriptのインストール方法は以下のページに詳しいです。

Linux/Macであれば、以下のようにすればインストール完了です。

$ curl https://raw.github.com/n8han/conscript/master/setup.sh | sh

conscriptをインストールした後、以下のようにしてSmartDoxをインストールします。

$ cs asami/dox

以下の2つのコマンドがインストールされます。

dox
SmartDoxコマンド
sdoc
SmartDocコマンド(互換用)
確認

SmartDoxの文章として以下のものをsample.orgという名前で用意します。

* 最初の章

最初の章の文章。

** 最初の節

最初の節の文章。

*** 最初の小節

最初の小節の文章。

| 名前 | 住所 |
|------+------|
| 太郎 | 横浜 |
| 花子 | 東京 |

以下のようにSmartDoxのdoxコマンドを起動し、 HTML5文書らしきものがsample.htmlで生成されればインストール成功です。 (デバッグ用のスナップショットが出力されますが、ご愛嬌ということで)

$ dox -html5 sample.org

SmartDoxは、まだPoC(Proof of Concept)の段階ですが、 ボクが日々の作業の中で色々と作り足していく予定なので、 いずれそれなりに機能が充実してくると思います。 その時になったらぜひ試してみてください。