読者です 読者をやめる 読者になる 読者になる

VBAHaskellの紹介 その1 (最初はmapF)

VBA

VBAHaskellHaskellを真似たVBAのライブラリである。

リスト処理系の関数や関数合成などの機能によって退屈な繰り返し処理を減らし、VBAをより面白くするのが目的だ。

その中でもmapFはコアとなる関数で、リンクしたgithubにあるHaskell_1_Coreモジュールの中で定義されている。*1
コールバック関数と配列を引数に取り、Haskellのmap関数と同様の動きをする。

リンクしたテストモジュール(test_module.bas)にあるデモ関数 vbaUnit を見ていただきたい。最初の7行はmapFのサンプルであり、実行すると以下のように表示される。*2

 

1 :    ------- mapF ----------

2 :    mapF(p_log, Array(1, 2, 3, 4, 5, 6, 7))
3 :       0 0.693147 1.098612 1.386294 1.609437 1.791759 1.945910
4 :    mapF(p_minus(3), iota(1,15))
5 :       2 1 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12
6 :    mapF(p_minus(, 3), iota(1, 15))
7 :       -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12
8 :

2. の第1引数であるp_logは対数関数(logN)を指す一種の関数ポインタ。logNは2変数関数だが、第2引数は省略可能なので実質的に1引数関数と考えることができる。(省略時は自然対数

結果はHaskellのmapと同様、列 [1, 2, 3, 4, 5, 6, 7]の各要素に対するLogの値が3行目に出力されている。

これが2変数関数だったらどうか。
減算関数であるminusのポインタp_minusを使う例が4. と6. である。
p_minusに引数を与えてp_minus(3), p_minus(, 3)となっているが、これらはそれぞれ1番目の引数と2番目の引数を特定の値に束縛したものである。

C++で言えば std::bind1st および std::bind2nd に相当する。 

4. では第1引数を3に束縛しているので
3-1, 3-2, 3-3, 3-4, 3-5, 3-6, 3-7, 3-8, 3-9, 3-10, 3-11, 3-12, 3-13, 3-14, 3-15
が、6. では第2引数を3に束縛しているので、
1-3, 2-3, 3-3, 4-3, 5-3, 6-3, 7-3, 8-3, 9-3, 10-3, 11-3, 12-3, 13-3, 14-3, 15-3
の計算結果が出力されている。*3

mapFに限らず、コールバックとして渡せる関数のシグネチャパターンは1種類しかないが、片方の引数を束縛することができる。普通にネストすることによる合成関数の作成や、関数の列をfoldlやfoldr系の関数に渡すことによって任意個数の関数の合成などもできるようにした。

dllを必要とするのが欠点だが、発展性のある面白いライブラリになることを期待しているので、リンクしたソースコードをダウンロードして遊んでもらえると嬉しい。

 

VBAHaskellの紹介 その2 (合成関数) - mmYYmmdd’s blog

ソースコード

github.com

 dllのバイナリ:

http://home.b07.itscom.net/m-yamada/VBA/mapM.dll

http://home.b07.itscom.net/m-yamada/VBA/mapM64.dll

 

 上記のうち、動かすのに必要なものは以下の6つのVBAモジュールとdllバイナリ。
C++のファイルは自分でコンパイル&ビルドしない場合は不要 *4
Haskell_0_declare.bas
Haskell_1_Core.bas
Haskell_2_stdFun.bas
Haskell_3_printM.bas
Haskell_4_vector.bas
Haskell_5_sort.bas
Haskell_6_iterator.bas
test_module.bas(テスト用モジュール)
misc_*.bas(テストモジュールで使用)
mapM.dll (32bit Office or 64bit Office)

basファイルはインポート*5すればいいが、Haskell_0_declare.bas と misc_random.bas にはAPI関数のDeclare文を記載しているので、dllはパスが通っているフォルダに置くかまたは自分でパスを補記する。またdllのDeclare名はmapM.dllだが、64bit Office 版のバイナリファイルは mapM64.dll なのでファイル名は変更する必要がある。
(2015/6/13に 64bit Office対応をした)

動作を確認した環境は、
Windows XP(32bit), Windows 7(64bit)
MS Office 2010以降(32bit, 64bit)

2010未満のOfficeでは、Haskell_1_Coreモジュールに2カ所ある LongPtr をLong に変更し、Declare文についている 'PtrSafe'宣言をすべて削除すれば使用可能。)

dllをコンパイル・ビルドする場合の環境はVisualStudio 2013以降のC++

*1:実質的にはC++APIの中にあって、VBA側は呼び出しているだけ

*2:小数点以下の桁数は省略して表記している

*3:iotaは連続した整数配列を出力する関数である

*4:VisualStudio2010以降でビルド確認

*5:プロジェクトエクスプローラー上で右クリック + ファイルのインポート(I)...