LoginSignup
0
0

More than 5 years have passed since last update.

VBAHaskellの紹介 その6 (foldl)

Last updated at Posted at 2015-04-30

(この記事ははてなブログ http://mmyymmdd.hatenablog.com/ の再掲です)

2015-04-14
VBAHaskellで実装しているfoldlは本物のHaskellと同様に、「2引数関数」、「初期値」、「対象リスト」の3つの引数を取る左畳み込み関数だ。VBAでラップはしておらず、Haskell_0_declareモジュールに宣言しているC++ API 1 をそのまま使う。

Declare Function foldl Lib "mapM.dll" ( _
                              ByRef   pCallback As Variant, _
                              ByRef   init As Variant, _
                              ByRef   matrix As Variant, _
                              Optional ByVal   axis    As Long = 1) As Variant

「2引数関数」である pCallbackには前回 VBAHaskellの紹介 その5(関数のシグネチャ)で解説したmake_funPointerで関数ポインタ化した構造を渡す。このとき引数は束縛しない。

例えば1から10までの整数の和を取る場合は次のように書けばよい。2

' 1から10 までの整数の和を求める
foldl(p_plus, 0, iota(1, 10))

これも含め同様の関数を列挙すると以下の8つある。

foldl 特定の軸に沿った左畳み込み(初期値指定あり)
foldr 特定の軸に沿った右畳み込み(初期値指定あり)
foldl1 特定の軸に沿った左畳み込み(初期値=先頭要素)
foldr1 特定の軸に沿った右畳み込み(初期値=先頭要素)
scanl 特定の軸に沿った左scan(初期値指定あり)
scanr 特定の軸に沿った右scan(初期値指定あり)
scanl1 特定の軸に沿った左scan(初期値=先頭要素)
scanr1 特定の軸に沿った右scan(初期値=先頭要素)

個々の機能の説明は省略するが、「特定の軸に沿った」とは何か?これはVBAの配列には2次元以上のものがあることが関係している。2次元の場合は縦方向と横方向では別の処理になるのだが、例をあげた方が早いと思う。

m = makeM(3,5,repeat(1,15)) : printM m 3 ' [3 * 5] の配列
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
printM foldl(p_plus, 0, m, 1) ' 1は省略可
3 3 3 3 3
printM foldl(p_plus, 0, m, 2)
5 5 5

4番目の引数を1にすると 縦に加算、2にすると横に加算された1次元配列が出力値となる。3次元の場合も同様だが出力は2次元配列になる。 4次元以上には対応していない。4

この引数となる関数は算術的な演算だけではない。applyFun 5 という「関数適用関数」を引数にすれば、任意個の関数の合成ができるのだ。

 ' 関数適用関数 これは要するに func(param) を呼び出している
 Function applyFun(ByRef param As Variant, ByRef func As Variant) As Variant

これを関数ポインタ化した p_applyFun を使って次のようにすると、初期値 init に配列形式で与えた1変数関数を左から順次適用して結果を出力する。

 foldl(p_applyFun,  init,  関数配列)

そしてこの foldlp_applyFunの組み合わせをひとつのパターンとして関数にしてしまうこともできるのだ。6

サンプル7 にあるロジスティック漸化式、フィボナッチ数列、Newton法による多項式の求根などはこれを使っている。 これらの場合は関数配列と言っても同一関数のリピートである。 VBAでこんなことができるなんて、けっこう胸アツなんじゃないかと思う。

VBAHaskellの紹介 その7 (bind1stとbind2nd)
VBAHaskellの紹介 その5 (関数のシグネチャ)
VBAHaskellの紹介 その4 (Find)
VBAHaskellの紹介 その3 (FizzBuzz)
VBAHaskellの紹介 その2 (合成関数)
VBAHaskellの紹介 その1 (最初はmapF)
ソースコード:https://github.com/mYmd/VBA


  1. 遺憾ながらコンパイル時処理はしていない 

  2. plusとp_plusはHaskell_2_stdFunモジュールに定義 

  3. printMはデバッグウィンドウに配列を出力するユーティリティ 

  4. C++側で任意次元のSafeArray構造体をハンドリングする方法がわからないし、利用機会もあまりないと思っている。 

  5. Haskell_1_Coreモジュール 

  6. Haskell_1_Coreモジュールのfoldl_Funsなど 

  7. test_moduleのSub vbaUnit 

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0