(邦訳:言語埋込みのためのロード時メタプログラミングを用いた実用的拡張)
シェア マクシミリアン パスカル (株)ディー・エヌ・エー |
[背景]言語仕様に近いライブラリインタフェース(EDSLs)
[問題]アドホックな実装方法とそれによる落とし穴
[貢献]EDSLをプログラミング言語機能として利用するための実用方法
[問題]アドホックな実装方法とそれによる落とし穴
[貢献]EDSLをプログラミング言語機能として利用するための実用方法
本研究では有用性が高く意外性の少ない言語埋め込みを目指したアーキテクチャの研究と開発を行った.
特定の問題群を表現しその解決を達成するにあたって汎用のプログラミング言語ではなく専用のドメイン専用言語(domain-specific languages, DSLs)が適切な道具となる.たとえば,データーベースへの問合せに特化されているSQLがそのような言語の1つとして挙げられる.ある用途に限られていることこそがDSLの利点である.DSLは本質的なところだけに焦点を当てることで,表現方法とともにそのドメインに特化した最適化を可能にできる.
DSLの問題点は,新しいプログラミング言語の開発と環境の提供にかかる初期投資がやや高いことである.そのコストを回避する方法として,DSLを独立にせず,HaskellやRubyやScalaなどの汎用の言語の中に組み込むことが提案され,近年普及している.関数呼び出しの組合せでDSLの使用を想起させるように関数の設計とその命名を工夫するのが,この方法の本質である.
こうした埋め込みDSL(embedded DSLs, EDSLs)は通常のライブラリーと区別が付かないことが多い.たとえば,関数型言語で一般的な「map」や「filter」などの関数はリスト処理のためのEDSLと見なすことができる.逆に,この言語埋め込みの概念そのものをライブラリー設計の向上に用いることもできる.さらに,EDSLの「プログラム」自体を具象化されるように設計することでドメインに特化した最適化または解析も可能になる.
ところが現在のEDSLの概念は本来的に言語のエミュレーションにすぎない.EDSLの実装レベルで考えると,その実装に使われるホスト言語の言語機構(シンタクスマクロであれ,関数であれ)と実装されるEDSLとの間には直接的な意味的つながりがない.
このような状況は,DSLの性能や信頼性,一般的な有用性を劣化させがちである.たとえば,複数のEDSLとホスト言語間の隔離を保証するのが困難になる.
上記の問題にたいし本研究では2つのステップまたはプロトタイプのフレームワークによって実用的な解決方法をJava上で開発した:
① Implicit Staging: ホスト言語の特定のメソッドなどの要素を「トークン」としてEDSLと関係づけることで,EDSLを明示的な存在にする.この関係情報をもとに特定のEDSLの式を実行直前にコードから抽出し,ホスト言語のコードから分離することで,EDSLコードとしての静的な処理,すなわち最適化などを可能にする.
② Tame Staging: EDSLへの言語インタフェースを改善するためにJavaのアノテーション機能を用いる.これはインタフェースを平易化するだけでなく,自動的なドキュメンテーションをも可能にする.EDSL式を静的に前処理する手法と異なり,EDSLの式が実行時に動的に構成され,処理され,キャッシュされるため,冗長な計算を避けることができる.
これらのプロトタイプはロード時メタプログラミングの技術をベースにして実装されているので,Java言語の標準の範囲内で実現されている.このため,本研究ではEDSLをホスト言語の完全な機能(first-class feature)とするまでには到っていない.しかしながら提案した機能は,将来の新しい言語設計に盛り込むべき望ましい機能であると考えている.
特定の問題群を表現しその解決を達成するにあたって汎用のプログラミング言語ではなく専用のドメイン専用言語(domain-specific languages, DSLs)が適切な道具となる.たとえば,データーベースへの問合せに特化されているSQLがそのような言語の1つとして挙げられる.ある用途に限られていることこそがDSLの利点である.DSLは本質的なところだけに焦点を当てることで,表現方法とともにそのドメインに特化した最適化を可能にできる.
DSLの問題点は,新しいプログラミング言語の開発と環境の提供にかかる初期投資がやや高いことである.そのコストを回避する方法として,DSLを独立にせず,HaskellやRubyやScalaなどの汎用の言語の中に組み込むことが提案され,近年普及している.関数呼び出しの組合せでDSLの使用を想起させるように関数の設計とその命名を工夫するのが,この方法の本質である.
こうした埋め込みDSL(embedded DSLs, EDSLs)は通常のライブラリーと区別が付かないことが多い.たとえば,関数型言語で一般的な「map」や「filter」などの関数はリスト処理のためのEDSLと見なすことができる.逆に,この言語埋め込みの概念そのものをライブラリー設計の向上に用いることもできる.さらに,EDSLの「プログラム」自体を具象化されるように設計することでドメインに特化した最適化または解析も可能になる.
ところが現在のEDSLの概念は本来的に言語のエミュレーションにすぎない.EDSLの実装レベルで考えると,その実装に使われるホスト言語の言語機構(シンタクスマクロであれ,関数であれ)と実装されるEDSLとの間には直接的な意味的つながりがない.
このような状況は,DSLの性能や信頼性,一般的な有用性を劣化させがちである.たとえば,複数のEDSLとホスト言語間の隔離を保証するのが困難になる.
上記の問題にたいし本研究では2つのステップまたはプロトタイプのフレームワークによって実用的な解決方法をJava上で開発した:
① Implicit Staging: ホスト言語の特定のメソッドなどの要素を「トークン」としてEDSLと関係づけることで,EDSLを明示的な存在にする.この関係情報をもとに特定のEDSLの式を実行直前にコードから抽出し,ホスト言語のコードから分離することで,EDSLコードとしての静的な処理,すなわち最適化などを可能にする.
② Tame Staging: EDSLへの言語インタフェースを改善するためにJavaのアノテーション機能を用いる.これはインタフェースを平易化するだけでなく,自動的なドキュメンテーションをも可能にする.EDSL式を静的に前処理する手法と異なり,EDSLの式が実行時に動的に構成され,処理され,キャッシュされるため,冗長な計算を避けることができる.
これらのプロトタイプはロード時メタプログラミングの技術をベースにして実装されているので,Java言語の標準の範囲内で実現されている.このため,本研究ではEDSLをホスト言語の完全な機能(first-class feature)とするまでには到っていない.しかしながら提案した機能は,将来の新しい言語設計に盛り込むべき望ましい機能であると考えている.
(2016年6月7日受付)