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

VBAHaskellの紹介 その7 (bind1stとbind2nd)

VBA

VBAHaskellにbind1stとbind2ndを追加した。C++の<functional>にあるのとだいたい同じだが、VBAHaskellにおいては関数は初めから何らかの形で束縛されているので、あまり使う場面はないと思う。意味的には引数の"再"束縛なので rebind と名付けるべきなのかもしれない。プレースホルダになっている場所ある値で束縛するわけだが、が1stで何が2ndかが自分でも少々わかりにくいのだ。

これを説明するために、VBAHaskellの紹介その5(関数のシグネチャ)で少し紹介した「関数ポインタ的なもの」についてもっとはっきり示したい。

VBA関数 "func" に対応する p_func  *1  の実体は次の配列だ。

p_func = Array ( AddressOf  func, _
                        placeholder, _             ' 第1引数のプレースホルダ
                        placeholder, _             ' 第2引数のプレースホルダ
                        placeholder)                ' 関数であるフラグ

AddressOf funcはLong値として扱っている。*2 placeholderAPI で作っている特殊な値で、一種のマジックナンバーと考えてよい。「関数であるフラグ」としてもplaceholder を流用しているが、これは手抜きに過ぎない。別に何でもよかったのだ。

想像できるように、第1引数もしくは第2引数を束縛したものは以下のものになっている。

p_func(3) = Array ( AddressOf func, _
                            3,                 _         ' 第1引数は3に束縛
                            placeholder, _         ' 第2引数のプレースホルダ
                            placeholder)            ' 関数であるフラグ 

p_func (, 3) = Array ( AddressOf func, _
                               placeholder, _      ' 第1引数のプレースホルダ
                               3,                 _      ' 第2引数は3に束縛
                               placeholder)         ' 関数であるフラグ

bind1stとbind2ndは次のものになる。*3

bind1st(p_func(3), 100) = Array ( AddressOf func, _
                                              3                 ,  _  ' 第1引数は変更なし
                                               placeholder, _  ' 第2引数のプレースホルダ
                                               placeholder)     ' 関数であるフラグ  

bind2nd(p_func(3), 100) = Array ( AddressOf func, _
                                            3,                   _   ' 第1引数は変更なし
                                            100,               _    ' 第2引数は100に束縛
                                            placeholder)        ' 関数であるフラグ

ややこしいのは関数がネストされた合成関数の場合だ。

p_func(p_func, p_func(, 2)) =
    Array ( AddressOf func, _
              Array ( AddressOf func, placeholder, placeholder, placeholder), _
              Array ( AddressOf func, placeholder, 2, placeholder), _
              placeholder  )

これに対して、bind1st や bind2nd を作ったらこういう状態になっている。

bind1st(p_func(p_func, p_func(, 2)) , 3 ) =
     p_func(p_func(3, 3), p_func(, 2)) =
            Array ( AddressOf func, _
                  Array ( AddressOf func, 3, 3, placeholder), _
                  Array ( AddressOf func, placeholder, 2, placeholder), _
                  placeholder
             )  

bind2nd(p_func(p_func, p_func(, 2)) , 3 ) =
     p_func(p_func, p_func(3, 2)) =
         Array ( AddressOf func, _
             Array ( AddressOf func, placeholder, placeholder, placeholder), _
             Array ( AddressOf func, 3, 2, placeholder), _
             placeholder
         )  

 product_set関数 *4 のパフォーマンスをあげるのにこれらを使った。

# 2015/5/17 : 関数の内容を文字列化するユーティリティ関数 dumpFun を Haskell_3_printMモジュール に追加した。

 

VBAHaskellの紹介 その6 (foldl) - mmYYmmdd’s blog

github.com

 

*1:ヘルパ関数make_funPointerを使って作れる

*2:32bit Officeだから。まだ64bit対応はできていない。

*3:記述に誤りがあったので訂正:2015/5/17

*4:Haskell_4_vectorモジュール