Haskell DSLによる複数プラット...

30
Haskell DSLによる複数プラット ホーム・複数言語コード生成 今井 敬吾 () ITプランニング 2012. 3. 23 次世代ソフトウェアの開発支援環境(公益財団法人 科学技術交流財団) @ 愛知県立大学サテライトキャンパス

Transcript of Haskell DSLによる複数プラット...

Page 1: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

Haskell DSLによる複数プラットホーム・複数言語コード生成

今井 敬吾(有) ITプランニング

2012. 3. 23次世代ソフトウェアの開発支援環境(公益財団法人 科学技術交流財団) @ 愛知県立大学サテライトキャンパス

Page 2: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

私について

(有)ITプランニング所属プログラマー(C++/Java/Obj-C/Haskell/OCaml, スマートフォン/Web開発等) / SEとして働く傍ら、

論文執筆・関数型言語の (草の根的) 普及活動に従事

名古屋大学 情報科学研究科 修了(阿草・結縁研)

2012年3月 博士(情報科学) 取得見込み並行分散計算(π計算/CCS/CSP)の関数プログラミングにおける応用を研究(していた)

2

(紹介スライド4枚)

Page 3: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

(有)ITプランニングについて

• 金融業向けに株価/FXチャートを受託開発

• 関数型プログラミング言語を利用・業務において6年の使用経験をもつ・普及活動:セミナー講師(国立情報学研究所、(株)豆蔵)・イベント主催・

  書籍執筆など

• 定理証明系Coqなど形式手法を導入

3

Page 4: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

宣伝• 書籍 入門OCaml・Scala実践プログラミング

• スタートSML# 2012/3/25(日)14:00-@名大理1-109

• 関数型プログラミング言語SML#の勉強会

• 招待講演:大堀 淳 教授 (東北大学) ほか

• 詳しくは http://tinyurl.com/smlnagoya 参照、参加については今井( [email protected] まで)

4

Page 5: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

• 金融業向けに株価/FXチャートを受託開発

(有)ITプランニングの製品(一部)

5

http://www.itpl.co.jp/

Page 6: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

金融チャートとは• 投資家に、相場の客観的な分析手法を提供するツール

• テクニカル分析

• 売買シグナル

• いつでも、どこでも、どんな端末でも使いたい

6

Page 7: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

テクニカル分析と売買シグナル

• テクニカル分析 • 売買シグナル

7

過去のデータから統計的手法を用いて未来の値動きを予測するcf. ファンダメンタルズ分析

HTML5チャート テクニカル分析計算定義書今井宜洋!

平成 24 年 1 月 31 日

1 トレンド系1.1 移動平均移動平均はパラメータN に対して次で定義される線を描画します。

MA(N,X) =1N

N!1!

i=0

R終値(X ! i)

1.2 ボリンジャーバンドボリンジャーバンドはパラメータNに対して次で定義されるBol(±2, N,X), Bol(±1, N,X), Bol(0, N, X)の計 5本の線を描画します。パラメータの初期値は 25です。

!(N,X) =

"####$

N!1!

i=0

%R終値(X ! i) ! AV G

&R終値(X), · · · , R終値(X ! N + 1)

'(2

N

Bol(K, N, X) = MA(N, X) + K!(N, X)

1.3 エンベロープMA(N), Env(N, + ! A), Env(N,+ ! 2A)の合計 5本の線を描画します。パラメータの初期値はN = 25, A = 1.0です。

Env(N,A, X) = MA(N, X) ")

1 +A

100

*

!有限会社 IT プランニング システム開発部

1

例:移動平均

赤:短期(N=5)

黄:中期(N=20)

緑:長期(N=90)

テクニカル分析で特定の条件が成立した時、売買を促すサイン

例:移動平均線の  ゴールデンクロス、デッドクロス

短期線が長期線を上に交わると、上昇トレンドが続きやすい

→買いシグナル

反対に、短期線が長期線を下に交わると、下降トレンドが続きやすい

→売りシグナル

投資家に、客観的な指標を提供する

Page 8: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

f

多様な取引プラットホーム

• Java Applet

• Windows (C++)

• Adobe Flash (ActionSctipt)

• Webブラウザ(JavaScript/HTML5)

• 携帯(docomo, SoftBank(Java)/AU(BREW))

• iPhone (Objective-C)

• Android (Java)

8

「いつでも、どこでも、どんな端末でも」の結果:

➡ 6言語, 9種類の環境で金融チャートを納品

Page 9: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

開発/メンテナンスコストの増大

• 仕様書・テスト:「この数列は仕様通りに生成されているか?」

スクリーンショットによる既存バージョンとの比較「要求:Windows版と同じチャートを出して下さい」

• 障害管理:特定環境でバグが見つかった時「docomo携帯版の一目均衡表の計算が一日ずれている」

「Windows版のパラボリックのドテンのタイミングが他と違う」

→ 残り8環境でも不具合調査が必要

• (コスト圧力:値下げ要求、オフショアとの競合)9

Page 10: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

コード再利用の試み• ビジネスロジック部は再利用の余地あり

(テクニカル分析や売買シグナル等)

• …が、ソースもバイナリも直接の再利用は不可:

× Cで共通ライブラリを作成 e.g. lib*.a/.so, *.dll, JNI (Java Native Interface)

 → NG : Java Applet, 携帯, Flash, ブラウザ

× Javaとネイティブ両方で動作するスクリプト言語 e.g. Python / Jython, Ruby / JRuby

 → NG : Flash, JavaScript, ブラウザ

10

Page 11: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

テクニカル分析DSL:Haskell/Tek

• 多用途に再利用できるコード生成DSL

‣ C, Javaコード生成

‣ イミディエイト評価 (ランダム実行など)

‣ TeXドキュメント生成 (未実装)

• Haskell上の埋め込みDSL (embedded DSL)

‣ Haskellの言語機能(型推論や高階関数)の恩恵を受けられる

11

Page 12: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

テクニカル分析DSL Haskell/Tekによる 仕様記述とコード生成

12

Haskell/Tekコード

C言語プログラム

Cコンパイラ iPhone版

Javaプログラム

JavaScriptプログラム

TeX仕様書ソース

Javaコンパイラ

Android版

イミディエイト実行

Page 13: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

ma n i = sum_close (i-(n-1)) i candles / toFloat n

Haskell/Tekコードの例:移動平均

13

i-(n-1)日目からi日目までの終値(close)の和を

i日目における

n日移動平均とは

nで割る

float accum0 = 0.0F;

for (int i0 = i - iparam[0] + 1; i0 <= i; i0++) { accum0 = accum0 + i_get(candles, i0).close;}i_put(series[0], i, accum0 / (float) iparam[0]);

生成されるCコード:

Haskell/Tek:

HTML5チャート テクニカル分析計算定義書今井宜洋!

平成 24 年 1 月 31 日

1 トレンド系1.1 移動平均移動平均はパラメータN に対して次で定義される線を描画します。

MA(N,X) =1N

N!1!

i=0

R終値(X ! i)

1.2 ボリンジャーバンドボリンジャーバンドはパラメータNに対して次で定義されるBol(±2, N,X), Bol(±1, N,X), Bol(0, N, X)の計 5本の線を描画します。パラメータの初期値は 25です。

!(N,X) =

"####$

N!1!

i=0

%R終値(X ! i) ! AV G

&R終値(X), · · · , R終値(X ! N + 1)

'(2

N

Bol(K, N, X) = MA(N,X) + K!(N,X)

1.3 エンベロープMA(N), Env(N, + ! A), Env(N,+ ! 2A)の合計 5本の線を描画します。パラメータの初期値はN = 25, A = 1.0です。

Env(N,A, X) = MA(N, X) ")

1 +A

100

*

!有限会社 IT プランニング システム開発部

1

Page 14: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

例2: ボリンジャーバンド

14

sigma_i n ma i = sqrt_ (sum_iter (i - n + 1) i dist) / toFloat n where dist i = pow2_ (close_at i - ma)

bol (n,a,b) i = let_ "ma" (MA.ma n i) $ \ma -> let_ "sigma" (sigma_i n ma i) $ \sigma -> tup5 (ma + b*sigma, ma + a*sigma, ma, ma - a*sigma, ma - b*sigma)

Haskell/Tek:

HTML5チャート テクニカル分析計算定義書今井宜洋!

平成 24 年 1 月 31 日

1 トレンド系1.1 移動平均移動平均はパラメータN に対して次で定義される線を描画します。

MA(N,X) =1N

N!1!

i=0

R終値(X ! i)

1.2 ボリンジャーバンドボリンジャーバンドはパラメータNに対して次で定義されるBol(±2, N,X), Bol(±1, N,X), Bol(0, N, X)の計 5本の線を描画します。パラメータの初期値は 25です。

!(N,X) =

"####$

N!1!

i=0

%R終値(X ! i) ! AV G

&R終値(X), · · · , R終値(X ! N + 1)

'(2

N

Bol(K, N, X) = MA(N,X) + K!(N,X)

1.3 エンベロープMA(N), Env(N, + ! A), Env(N,+ ! 2A)の合計 5本の線を描画します。パラメータの初期値はN = 25, A = 1.0です。

Env(N,A, X) = MA(N,X) ")

1 +A

100

*

!有限会社 IT プランニング システム開発部

1

HTML5チャート テクニカル分析計算定義書今井宜洋!

平成 24 年 1 月 31 日

1 トレンド系1.1 移動平均移動平均はパラメータN に対して次で定義される線を描画します。

MA(N,X) =1N

N!1!

i=0

R終値(X ! i)

1.2 ボリンジャーバンドボリンジャーバンドはパラメータNに対して次で定義されるBol(±2, N,X), Bol(±1, N,X), Bol(0, N, X)の計 5本の線を描画します。パラメータの初期値は 25です。

!(N,X) =

"####$

N!1!

i=0

%R終値(X ! i) ! AV G

&R終値(X), · · · , R終値(X ! N + 1)

'(2

N

Bol(K, N, X) = MA(N,X) + K!(N,X)

1.3 エンベロープMA(N), Env(N, + ! A), Env(N,+ ! 2A)の合計 5本の線を描画します。パラメータの初期値はN = 25, A = 1.0です。

Env(N,A, X) = MA(N,X) ")

1 +A

100

*

!有限会社 IT プランニング システム開発部

1

i日目より過去n日間に関する分散σ(n,i)

ボリンジャーバンド(5つ組)

高階関数 sum_iter i j f = Σ (x is i to j) f(x)

他のテクニカル(移動平均)の呼び出し

Page 15: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

ボリンジャーバンド:生成されるC言語コード

15

float accum0 = 0.0F;

for (int i0 = i - iparam[0] + 1; i0 <= i; i0++) { accum0 = accum0 + i_get(candles, i0).close;}

float ma = accum0 / (float) iparam[0];float accum1 = 0.0F;

for (int i1 = i - iparam[0] + 1; i1 <= i; i1++) { float x = i_get(candles, i1).close - ma; accum1 = accum1 + x * x;}

float sigma = sqrt(accum1 / (float) iparam[0]);

i_put(series[0], i + 0, ma + fparam[1] * sigma);i_put(series[1], i + 0, ma + fparam[0] * sigma);i_put(series[2], i + 0, ma);i_put(series[3], i + 0, ma - fparam[0] * sigma);i_put(series[4], i + 0, ma - fparam[1] * sigma);

分散σ

移動平均

ボリンジャーバンド

Page 16: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

Haskell/Tek=(現状では) 性能の良いC言語マクロ

16

float accum0 = 0.0F;

for (int i0 = i - iparam[0] + 1; i0 <= i; i0++) { accum0 = accum0 + i_get(candles, i0).close;}

float ma = accum0 / (float) iparam[0];float accum1 = 0.0F;

for (int i1 = i - iparam[0] + 1; i1 <= i; i1++) { float x = i_get(candles, i1).close - ma; accum1 = accum1 + x * x;}

float sigma = sqrt(accum1 / (float) iparam[0]);

i_put(series[0], i + 0, ma + fparam[1] * sigma);i_put(series[1], i + 0, ma + fparam[0] * sigma);i_put(series[2], i + 0, ma);i_put(series[3], i + 0, ma - fparam[0] * sigma);i_put(series[4], i + 0, ma - fparam[1] * sigma);

移動平均のコードが展開される

bol (n,a,b) i = let_ "ma" (MA.ma n i) $ \ma -> let_ "sigma" (sigma_i n ma i) $ \sigma -> tup5 (ma + b*sigma, ma + a*sigma, ma, ma - a*sigma, ma - b*sigma)

移動平均の呼び出し

•別の見方:型チェック・高階関数(マクロ)等を備えたメタプログラミングライブラリ•値呼びと名前呼びを少し注意して区別する必要がある(やや欠点)

Page 17: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

適用可能性

• 移動平均

• 指数平滑移動平均

• 一目均衡表

• ボリンジャーバンド

• パラボリック

• エンベロープ

• RSI

• ストキャスティクス

• DMI

• RCI

• モメンタム

• ROC

• MACD

• %Rオシレーター17

本手法により14種のテクニカル分析に対応

Page 18: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

実装コストの減少

• 開発:15人日 ... Haskell/Tek C言語版 (iOS向け)

7人日 ... テクニカル分析1人日 ... Haskell/Tek Java版 (Android向け)

• メンテナンスコストも実感として下がっている

18

Page 19: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

総コード行数

• Haskell 1758行(うちテクニカル分析777行, C生成部 981行)

➡生成されたC言語コード 2077行

➡生成されたJavaコード 2257行

19

Page 20: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

Haskell/Tekの実装

Page 21: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

なぜHaskellか1. オープンソースのパーザ/プリンタが沢山あった

• C, Java, JavaScript, ... そこそこ枯れたライブラリが多数

• 代数的データ型のおかげで構文木操作が(JavaやCより)簡単

• 今回はLanguage.C.Quote(*1)を用いた

2. EDSL との親和性が高い

• 遅延評価、関数呼び出しの構文が「軽い」、型クラス

21

(*1) language-c-quote: http://hackage.haskell.org/package/language-c-quote

Page 22: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

実装:Language.C.Quoteの利用

• Haskellの言語拡張により、Haskellの中にCのコード断片を記述可能に

• C言語構文木の生成が手軽にできた

22

do .. (bodyExp, bodyStmts) <- .... tell [C.BlockStm [cstm| for(int $id:counter=$f ; $id:counter<=$t ; $id:counter ++) { $items:bodyStmts $items:(makeAssigns initVars bodyExp) } |] ];

C言語コード

Haskellコード

Page 23: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

EDSLの概要• Haskell/Tekの関数群で記述したデータが、C/Javaに変換される(Haskellの全体が、CやJavaに変換できるわけではない)

• より詳細には

23

Haskell/Tekコード

C言語プログラム

実行形式(.exeなど)

Haskellコンパイラ 実行

実行

Javaプログラム

-- テクニカル記述

ma n i = sum_close (i-(n-1)) i candles / toFloat n

-- テクニカル記述をCコードとして印字

main = printCCode ma-- main = printJavaCode ma -- Java-- main = randomRun ma -- イミディエイト実行

イミディエイト実行

Page 24: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

EDSLの実装(案1)• EDSLの構文木を表す型を定義し、そこから変換する

• 比較的普通の方法

• Tek型(中間データ構造)を定義する必要がある

24

Tek型(EDSLの構文木型)

CLanguage型

JavaLanguage型

HaskellRunner型

printCCode

printJavaCode

randomRun

Haskell/Tek関数群

Page 25: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

EDSLの実装(案2):

タグレス実装• Kiselyovら(*2)の方法 (こちらを採用)

• 中間データ型を介さず、型クラスによって実装する

25

(*2) Finally Tagless, Partially EvaluatedTagless Staged Interpreters for Simpler Typed Languages, Journal of Functional Programming 19(5):509-543, 2009

CLanguage型

JavaLanguage型

HaskellRunner型

Haskell/Tek関数群(型クラス Lang l)

gen

gen

gen

(genをターゲットの型について多重定義)

Page 26: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

その他の関数型DSL

Page 27: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

参考:DSLと関数型言語(1)

LexiFi• LexiFi(*3)

• 関数プログラミングを用いて金融派生商品の契約を記述できる OCaml 内 DSL。

• デリバティブのリスク評価と契約執行を1つのDSL

記述から導出

27 LexiFi社Webページ(フランス)(*3)http://www.lexifi.com/

Page 28: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

参考:DSLと関数型言語(2)

Paraiso• Paraiso (*4)

• 宇宙物理学シミュレーションのDSL記述より 多数の並列計算機へコンパイル

• CUDA+MPI, OpenMP

• C言語の似たような繰り返しが無くなり、記述が容易に→様々な最適化をラピッドに試せる

28(*4)http://paraiso-lang.org/wiki/index.php/Main_Page

Page 29: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

まとめ

• C・Java向けのテクニカル分析コードを生成するHaskell上のDSLを開発

• 実装フェーズの効率化

• 「より書きやすく安全な」C言語マクロとしてのEDSL

29

Page 30: Haskell DSLによる複数プラット ホーム・複数言語コード生成proofcafe.org/~keigoi/2012Mar-haskelldsl.pdf · Haskell DSLによる複数プラット ホーム・複数言語コード生成

今後の課題• よりGUIに近いコードの生成

• スクロール、日付計算、座標変換などまだまだDSL化できるはず

• 証明付きDSL

• 数列計算の正しさをCoqで証明する

• コード生成部にバグが無ければ、完全にバグがないコードを生成可能

30