Programmingの最近のブログ記事

Scalaを始めたばかりでJavaで書いてたことをどう書くのかよく混乱するので、メモ。

項目JavaScala
クラスオブジェクトFoo.classclassOf[Foo]
例外ハンドリングtry { .. }
catch (Ex1 e) { .. }
catch (Ex2 e) { .. }
try { .. } catch {
case e1: Ex1 => ..
case e2: Ex2 => ..
}
リスト/配列作成list = new ArrayList() list = List[T]()
array = Array[T]()
リスト追加N/Alist = list ::: List(x)
配列追加list.add(x)array ++ List(x)
マップ作成map = new HashMap()map = Map.empty
マップ追加map.put(x, y)map += x -> y
シングルトンstaticでメンバに保持object { ... }
イテレーションfor (i : list) ...list foreach (i=> { ... })
キャスト(Foo) barbar.asInstanceof[Foo]
型判定foo instanceof Foofoo.isInstanceof[Foo]
内部型Foo.BarFoo#Bar
シングルトンの型N/Aobj.type
型パラメータ制約class Foo<T extends Bar>class Foo[T <: Bar]
(逆もclass Foo[T >: Bar]で可能)
オブジェクトObjectAny (primitiveを含む場合)
AnyRef

なんかまだまだあった気がするけど、気付いたら追加しよう。 なお、必ずしもsemanticalに同一ではないので注意してください。

Scalaを使ったフレームワークにspecsというのがあります。 Behaviour-Driven Design frameworkといっています。

乱暴な言い方をすれば、Test driven developmentと、Domain driven designを融合したもの、という感じです。 Test drivenといえばJUnitなどですっかりおなじみですが、specsはScalaの特徴を生かして、仕様がより自然に(ノイズが少なく)書けることが特徴でしょう。

Domain driven designは、特定の技術を表すものではなく、設計の考え方です。複雑なソフトウェアの設計をドメイン知識をうまく使いながら行おうといういうものと思われます。 比較的新しい考え方のようで、OOPSLA 2007でBoFが開かれたそうです。

そんな感じなので、specsにはドメイン知識としての仕様を記述して、それをチェックする機能が備わっています。

specsはScalaをベース言語としているので、当然普通にJavaとして動作するのですが、DSLのコンテキストで考えたときに、テストだけではなく純粋に動作する仕様としてどのように考えられているのか、という点についてはまだよくわかっていません。 もともと仕様をデザインするためのもの(design framework)なので、そのままの形で実稼動するソフトウェアにするのは本来の目的ではないのかもしれません。

でも、これをJUnitのように純粋なテストのためのフレームワークと考えるのもまた違うような気がします。 Scalaの言語機能を考えると、もっとポテンシャルがあるように思います。

というわけで、まだまだ勉強中なのですが、specsのソースコードはScalaの勉強にはいいですね。

何となく気が向いたので、A Tour of Scalaを翻訳しました。 さらに気が向いたらツアーの内容も訳そうかな...。

ところで先日気にしていたスタックに関してですが、リファレンスを読む限り、tail-recursionはスタックを消費しないようにできているらしいです。


A Tour of Scala

Scalaはモダンでマルチパラダイムなプログラミング言語で、プログラムパターンを簡潔、エレガント、かつ型安全に表現することができます。 オブジェクト指向および関数型言語の機能をスムーズに統合しています。

Scalaはオブジェクト指向

Scalaは全ての値がオブジェクトである、という点において純粋オブジェクト指向言語です。 型とオブジェクトの挙動はclassとtraitで記述されます。 クラスは多重継承の代わりにサブクラスや柔軟なミックスインベースのコンポジションで拡張することができます。

Scalaは関数型

Scalaは全ての関数が値である、という点において関数型言語でもあります。 Scalaは匿名関数を定義するための軽量な構文をもち、高階関数をサポートし、入れ子の関数を書くことができ、カリー化をサポートします。 Scalaのケースクラスとビルトインのパターンマッチングは、多くの関数型言語で使われている代数型をモデル化します。

さらに、Scalaのパターンマッチングの考え方と、right-ignoring sequence patternsを使うことにより、XMLデータを自然に処理することができます。 ここでは、クエリを作るのにsequence comprehensionsが便利です。 これらの機能により、ScalaはWebサービスを作るのに最適な言語となっています。

Scalaは静的型付き

Scalaは安全で一貫性のある抽象化を行うための静的な型システムを持ちます。 特に、型システムは以下をサポートしています。

  • ジェネリッククラス
  • varianceアノテーション
  • 型の上限、下限
  • オブジェクトメンバとしての内部クラスおよび抽象型
  • コンパウンド型
  • 明示型付き自己参照
  • ビュー
  • ポリモーフィックなメソッド

局所型推論機構により、ユーザが冗長な型情報を記述する必要はありません。 これらの機能の組み合わせにより、プログラムの安全な抽象化再利用や型安全な拡張が可能となります。

Scalaは拡張性がある

ドメイン固有のアプリケーションの開発は、しばしばドメイン固有言語(DSL)拡張を必要とします。 Scalaは言語機能のユニークな組み合わせにより、ライブラリによる言語機能の追加を簡単にしています。

  • 任意のメソッドが後置および中置演算子として使用可能
  • 対象型による自動クロージャ生成

これらの利用により、構文拡張やマクロ機能などをしなくても新しい文を定義することができます。

ScalaはJavaおよび.NETと相互利用可能

ScalaはJava 2 Runtime Environmentと相互利用可能です。 特に、Javaとのインタラクションは可能な限りスムーズになっています。 ScalaはJavaと同様なコンパイルモデル(セパレートコンパイル、動的ローディング)を持ち、既存のライブラリにアクセスすることができます。 .NETフレームワーク(CLR)もサポートされています。

  • A Tour of Scala: 抽象型
  • A Tour of Scala: アノテーション
  • A Tour of Scala: クラス
  • A Tour of Scala: ケースクラス
  • A Tour of Scala: classOf定義済関数
  • A Tour of Scala: コンパウンド型
  • A Tour of Scala: Sequence comprehensions
  • A Tour of Scala: Extractorオブジェクト
  • A Tour of Scala: ジェネリッククラス
  • A Tour of Scala: 暗黙パラメータ
  • A Tour of Scala: 内部クラス
  • A Tour of Scala: ミックスインクラスの作成
  • A Tour of Scala: 入れ子関数
  • A Tour of Scala: 匿名関数構文
  • A Tour of Scala: カリー化
  • A Tour of Scala: 自動型依存クロージャ生成
  • A Tour of Scala: 演算子
  • A Tour of Scala: 高階関数
  • A Tour of Scala: パッケージ
  • A Tour of Scala: パターンマッチング
  • A Tour of Scala: ポリモーフィックメソッド
  • A Tour of Scala: 正規表現
  • A Tour of Scala: シールドクラス
  • A Tour of Scala: Traits
  • A Tour of Scala: 型上限制約
  • A Tour of Scala: 型下限制約
  • A Tour of Scala: 明示型付き自己参照
  • A Tour of Scala: サブクラス化
  • A Tour of Scala: 局所型推論
  • A Tour of Scala: 統合型
  • A Tour of Scala: Variances(共変及び反変)
  • A Tour of Scala: ビュー
  • A Tour of Scala: XML処理

Scalaメモ

| | コメント(0) | トラックバック(0)

ちょっと最近気になる関数型言語、Scalaのメモ。

Overview

Scalaは、Javaとの親和性が高い静的型付き関数型言語で、2001年から開発されています。 開発元はこちらです。

関数型かつ純粋オブジェクト指向なので、Javaで苦手(不可能)とする以下のようなことをサポートしています。

  • プリミティブ型および関数のオブジェクトとしての扱い
  • staticの排除(代わりにシングルトンオブジェクトのネイティブサポート)
  • カリー化(currying)および高階関数(higher-order function)
  • 型推論機構
  • 遅延評価
  • trait (一種のmix-in)
    Javaのinterfaceに近いのですが、実装を持つことができます。
  • すべての識別子の中間演算子としての使用(a.func(b)はa func bと同じ、a + bはa.+(b)と同じ)
  • (配列とは異なる)リストのサポート
    配列とは、リストはimmutable(変更できない)、再帰的(内部にリストを含められる)、Lispのリストのようにさまざまなオペレーションがある、という点で違いがあります。
  • XML構文をサポート(プログラムの一部としてXMLが記述できる)
    たとえば、XMLを返す次のような関数が定義できます(インデントは見やすくするため)。 関数型言語なので、実行時の最後の評価値が返り値になり、明示的にreturnを使う必要はありません。
    def elm(attr: Any, content: Any) = {
      <data attr="{attr.toString}">
        {content}
      </data>
    }
    

これらの特徴により、プログラムをJavaにそっくりに書くこともできれば、関数型ばりばりのフォーマットで書くこともできます。Javaとのインタラクションを言語レベルでサポートしているので、Javaのプログラムをそのまま呼び出すことも可能です。 また、genericsなどJava 1.5+でサポートされた(無理のある)syntactic sugarが自然に書けるのもいいところです。


業務アプリへの適用可能性

関数型言語はある種の問題に対して非常にソリューションを書きやすいのですが、OCamlやHaskellなど、いままで業務の世界などであまり成功しているとはいえません。 その理由は、

  • 業務の世界は保守的なので新しい言語などの導入には慎重
  • 業務上、関数型のソリューションを必要とする場面が少ない

といったところでしょうか。

たとえば、RubyもRuby on Railsでそれなりの支持を得ていますが、メインストリームといえるほどの盛り上がりにはなっていないと思います。

Scalaの場合、Javaをネイティブサポートしていたり、普通に手続き型風にコードを書くことも可能だったり(構文も似ている)、結構気を使っている気がします。 ライセンスもBSDスタイルなので、それほど神経質になる必要がありません。

Javaのサポートについては、そもそもScalaプログラムをコンパイルすると、Javaのクラスになり、Scalaのライブラリを使って実行するようになっています。 加えて、Javaに「あったらいいな」と思える機能があるので、なかなか使えそうな気はします。

個人的には、プリミティブや関数をfirst class objectにしたり、高階関数が使えたりするのはとても便利です。JavaScriptでもできますし。 それと、静的型付け言語でコンパイル時に型チェックが行われるというのが、業務アプリの世界ではなじみやすいかもしれません。 RubyやJavaScriptなどの動的型付け言語は便利ですが、検証やテストが大変なので。


気になる点

ちょっと気になるのは、関数型言語の特徴を生かして書きたい場合、処理を再帰で書くことが多いのですが、メモリ効率や実行効率がどうなるかです。 たとえば、次のような例があります。

整数aとb(a <= b)の間の数の総和を求める。

def sumInts(a: Int, b: Int): Int = if (a > b) 0 else a + sumInts(a + 1, b)
  

この関数sumIntsは、aとbの差が大きければ再帰しまくるので、スタックを使っているとすればあっという間にあふれてしまいます。 tail recursionくらいは展開しているかもしれませんが...。

次は、クイックソートの例です。

def sort(xs: Array[Int]): Array[Int] =
  if (xs.length <= 1) xs
  else {
    val pivot = xs(xs.length / 2)
    Array.concat(
      sort(xs filter (pivot >)),
           xs filter (pivot ==),
      sort(xs filter (pivot <)))
  }
  

返り値の配列は引数とは異なるので、元の配列を保存する必要がない場合、余計にメモリを必要とします。 まぁ、これらが問題になるような場合には手続き的に書くことも可能なのですが。


開発環境

開発環境に関しては、Eclipseのプラグインが公開されており、Javaと同じような感覚で開発ができます。

Scalaの実行形式はJavaのバイトコードなので、デバッガを使うと、Scalaプログラム(ライブラリ含む)とJavaの間を行ったりきたりしながら実行されます。 Scalaで書かれた部分はScalaのコードとして表示されるため、きわめてシームレスなデバッグが可能です。


いずれにしても、これからどのようになっていくか、ちょっと楽しみです。

最近、ビジネスアプリケーションの世界でもDSLが注目を集めているようです。

Martin FowlerもDSLについての本を執筆中で、ドラフトを公開しています。

言語屋出身の私にとって、DSLの世界もなかなか興味深いので、簡単にまとめておきます。デザインパターンと同じように、全く新しい概念というわけではなく、既存の概念をうまく整理したものですね。

なお、Fowlerのサイトを参考にしていますが、本のドラフトに忠実に書いているわけではないので注意してください。

DSLとは

Domain Specific Languageの略。対語はGeneral Purpose Language(汎用言語)。 ある特定の目的のために特別にデザインされた言語。目的を達成するための機能さえあればよく、チューリング完全である必要もない。その代わり、目的を達成するために簡潔に記述できる。

DSLの利点をひとことで言えば、特定の目的のために無駄を省いて簡潔に記述できるところにある。

DSLは新しい概念ではなく、昔からいろいろな形で存在する。 例として、正規表現、SQLなどがある。正規表現は文字列処理というドメイン専用の言語であるし、SQLはデータベース操作が目的の言語である。これらの言語は「何でもできる」言語ではなく、ある特定用途に特化して簡潔に記述できるので、DSLである。

DSLは他の言語(例:Java)の中で使われることもある。 ただし、Javaそれ自体は汎用言語なので、DSLではない。

ライブラリやフレームワークとの違いは、ライブラリが"Push button API"とすれば、DSLは"Fluent API"だということである。 Push Button APIは、通常それ自身で意味的に完備(例:getPrice)であるが、Fluent APIはコンテキストに強く依存する(例:price)ことが多い。

品物を定義し、その値段を設定する例を書いてみる。

Push Button API (Java風味)

Item pen = new Item();
pen.setPrice(100);

Fluent API (Ruby風味)

pen :price => 100

どちらも同じことができるが、Fluent APIはノイズが少ない(余計なことを極力書かない)のが特徴である。

ここでは文字列表記をしているが、DSLは文字列であることもあれば、図表であることもある。MDD(Model Driven Development)で利用するモデル図も一種のDSLとみなすことができる。

DSLの種類

Fowlerの本に準じた種類わけは以下の通り。

External DSL

処理する言語(ホスト言語)とは別に作成したもの。例えば特定目的のスキーマ下のXMLもExternal DSLである(例: Antで使うbuild.xml)。

目的のために構文が自由に決められるため、シンプルに記述できる。 ノイズは通常きわめて少ないが、XMLのように多い場合もある。

当然専用のパーサが必要になる。

Internal DSL (Embedded DSL)

ホスト言語内に記述したもの。動的言語のRubyやLisp、マクロやテンプレートなどのsyntactic sugarが豊富な言語では比較的容易に実現可能だが、Javaなどでも可能。

記述はホスト言語が処理するので、専用のパーサは不要。ただし、ホスト言語の構文を逸脱できないので、ノイズは多くなりがち(括弧、セミコロン、キーワード、一時的な変数など)。

最近のJavaはsyntactic sugarが多く私はあまり好きではないが、この場合は有効に使える。

Javaで実現する場合、Method Chaining、Function Sequence、Annotation、Nested Functionなどのテクニックを使う。 ただ、それぞれ長所・短所があり、どれが良いと一概に言うことはできない。

たとえば、Method Chainingは比較的実現しやすいが、ノイズは結構多くあまり読みやすくない。Function Sequenceをstatic importとともに使うとよりシンプルに記述できるが、グローバルにメソッドや情報を持たなければいけないという弱点もある。

これらのハイブリッドで実現することもある。その場合はノイズを極力減らせるが、記述する内容によって記述方法が変わるので、分かりにくくなる(特に記述しにくくなる)可能性もある 。

Language workbench

DSLによる開発をするための環境を含んだ考え方。DSLは保存される表現、実行されるときの表現、そして編集するときの表現があるが、それらを中心となる抽象表現(≒Semantic Model)で表す。

DSLとそうでないものの境界はあいまい。一般用途の言語でも、特定用途に限って使うように制限されていればDSLと言えることもある。DSLでも、それが本来の目的以上の一般用途に使われればDSLとは言えない。

DSLでは、Semantic Modelと記述形式(構文)、実行形式は分離していることが望ましい。 保守が楽になるためである。

DSLはインタプリタ形式で実行されることもあれば、コンパイラ形式(コード生成)で実行されることもある。 Semantic Modelが分離していれば、これはあまり大きな問題ではない。 インタプリタ形式の場合はSemantic Modelを直接実行できるが、 コンパイラ形式にする場合はコード生成を行うので、 コード生成器の作成労力やパフォーマンス、実行環境(インタプリタを積めるかどうか)などのトレードオフである。

XMLは特定目的のスキーマの上でDSLとみなすこともできるし、そうでない場合もある。 Javaなどではパーサを作るのが簡単なのでXMLをDSLとして使うことが多いかもしれないが、表現上はタグだらけになる(=ノイズが多くなる)ので読み書きしにくいかもしれない。 これは独自構文のパーサを作る労力とDSLユーザの労力のトレードオフである。XMLを専用の編集ツールで隠蔽する手もあるが、これはLanguage workbenchのアプローチに近くなる。

コミュニケーションツールとしてのDSL

DSLはコミュニケーションツールとしての側面も持つ。

開発者にとってコミュニケーションを容易にすることももちろんだが、ユーザ(特にドメインエキスパート)とのコミュニケーションを容易にすることも可能である。 この場合、ドメインエキスパートはDSLを書くよりも読むことがきることがより重要。 もちろん書ければそれに越したことはないが、ドメインエキスパートはプログラマではないことに注意。

DSLを使うべきとき、そうでないとき

DSLの開発にはコストがかかるので、それに見合わないときは作るべきではない。

また、利用者がDSLを覚えるのに苦労するようでも意味がない。 複雑なライブラリの上にDSLを作って簡単に使えるようにする、などのメリットがなければならない。

機能範囲を絞ることも重要。 悪い例はAntで、相次ぐ機能拡張でわかりにくくなってしまった。

DSLが複雑なときは、場合によっては屋上屋を重ねることも有用。 以前から、設定ファイル(一種のDSL)ではこのようなことが行われてきた。 例えばsendmail.conf->CF、Makefile->imakefileなど。

DSLの作り方

DSLの作り方には、既存のライブラリのAPIに屋上屋を重ねる(ラップする)方法、ドメインエキスパートと作るモデルから入る方法、言語仕様から入る方法(特にembeddedの場合)などがある。

既存の言語のままでもDSLと言えることもある。

たとえば、COBOLのCOPY句を読み込んでJavaとのインタフェース用のプログラムを出力する場合、このCOPY句をJavaとのインタフェース用DSLと「みなす」ことも可能(COBOL言語仕様の一部のみを特定目的で使っていることがポイント)。 

Fowlerの本では、パーサやコンパイラ、コード生成などについても解説していますが、この辺は特に目新しいことはないので知ってる人は読む必要はないでしょう。

Hexameter 2.1.2をリリースしました.

Sourcceforgeからダウンロードできます.

変わったのは、SDOS 1.1用のテンプレートを用意したことだけですのでたいして大きな変化ではないですが、もしSDカードアダプタをお持ちの方でSDカードをアクセスしたいという奇特な(?)方がいらっしゃればぜひご利用ください. また、SDOS開発時に作成したいろいろ有用なルーチンも用意してますので、良かったら使ってみてください. 戦士カートリッジ版、1M ROMアダプタ版双方で動作するはずです.

つい昨日、このブログのCAPTCHA認証がちゃんとセットアップされていないことが明らかになり、直したばかりなのですが。

なんと、「妹認証」なるものがあるそうです。なんでも、妹の質問に答えることで認証されるそうです。動作デモも公開されています。ネタではなく、れっきとしたCAPTCHA認証モジュールです。

技術的には、
  • 日本語のTrueType Fontに対応している
  • 質問と答えをセットで設定できる
というところが興味深いですね。

プログラム本体はPHPです。配布パッケージ内に、画像がpngファイルおよびpsdファイルで格納されている(ただし、psdは私の持っているPhotoshop 6.0では開きませんでした。CS3も持っていますが試してません)ので、妹が嫌な人は画像を変えていろいろできそうですね。

ある意味、パスワードリマインダー的な使い方もできます(質問・答えを動的設定すればよい)し、anonymousかつ会員制サイトみたいなものも作れます。実のところ、意外に隙を突いたアイデアだと思います。

このアーカイブについて

このページには、過去に書かれたブログ記事のうちProgrammingカテゴリに属しているものが含まれています。

前のカテゴリはPC/Gadgetです。

次のカテゴリはSDカードです。

最近のコンテンツ アーカイブ

November 2008: 月別アーカイブ