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

  • 14
    いいね
  • 3
    コメント

(2016/07/04 追記)
パイプライン演算用のクラスモジュールvh_pipe.clsを追加した。


(2016-02-13 追記)
VBAHaskellの関数リファレンスページ。
VBAHaskell_reference.htm


2015/04/11

VBAHaskellはHaskellを真似たVBAのライブラリである。
リスト処理系の関数や関数合成などの機能によって退屈な繰り返し処理を減らし、VBAをより面白くするのが目的だ。
mapF はそのコアとなる関数で、リンクした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

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 (合成関数)

基本的には、
VBAコード添付済みExcelブック「VBAHaskellほぼ全部入り.xlsm」もしくはこっち、「VBAHaskellほぼ全部入り.xlsm」とそこに記載されたdllを落とせば使える。
(モジュールのインポートは面倒だし日本語コメントが文字化けしたりする)


ソースコード
https://github.com/mYmd/VBA
dllのバイナリ(github):
https://github.com/mYmd/VBA/blob/master/bin/mapM (32bit-Office用)
https://github.com/mYmd/VBA/blob/master/bin/mapM64 (64bit-Officey用)
(HP):
http://home.b07.itscom.net/m-yamada/VBA/mapM (32bit-Office用)
http://home.b07.itscom.net/m-yamada/VBA/mapM64 (64bit-Officey用)

上記のうち、動かすのに必要なものは以下のVBAモジュールとdllバイナリ。
(C++のファイルは自分でコンパイル&ビルドしない場合は不要)
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_utility.bas
misc_random.bas
vh_stdvec.cls
vh_pipe.cls(パイプライン演算子)
mapM.dll (32bit Office or 64bit Office)

basファイルとclsファイルはインポート 4すればいいが、Haskell_0_declare.bas と misc_random.bas にはAPI関数のDeclare文を記載しているので、dllはパスが通っているフォルダに置くかまたはLoadLibraryする。もちろん自分でDeclare文のところにパスを補記してもよい。またdllのDeclare名はmapM.dllだが、上に置いてある64bit Office版のバイナリファイルは区別するため mapM64.dll としたのでファイル名は mapM.dll に変更する。

対象とする環境は、
Windows XP(32bit), Windows 7(32bit, 64bit)~
MS Office 2010以降(32bit, 64bit)
(2010未満のOfficeでは、Haskell_1_Coreモジュールに2カ所ある LongPtr をLong に変更し、Declare文についている 'PtrSafe'宣言をすべて削除すれば使用可能。)

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


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

  2. ここでは小数点以下の桁数はすこし省略している 

  3. iotaは連続した整数配列を出力する関数(Haskell_4_vector.bas) 

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