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

VBAHaskellの紹介 その4 (Find)

VBA

きょう、いわゆる検索関数 "find_pred" を追加した。Haskell_1_Coreモジュールに入れている。

Function find_pred(ByRef pred As Variant, ByRef vec As Variant) As Variant

対象配列の中から条件に合致する値を探す関数で、第1引数のpredは検索における条件指定の述語で、第2引数のvecは対象配列だ。

自由度の高いpredを簡単に生成できるかどうかが検索の使い勝手を決めると思う。「指定した範囲に含まれる」とか「素数である」等の条件を述語オブジェクトとして生成するときに、いちいちヘルパ関数を定義したりするのは面倒なのでやりたくない。*1

find_predは単にループを回しているだけだが、合成関数の作成と呼び出しが簡単なので、シンプルに実装できた。

これを使って乱数列の中からある範囲内の数値を探すコードはこうなる*2

Points = mapF(p_rnd(0), repeat(100, 10000))
pred = p_mult(p_greater( , 29.9), p_less( , 29.99))
m = find_pred(z, Points)

こう書くと pred は 29.9 < x かつ x < 29.99  を満たす x に1を、そうでない x に0を返す関数になる。ラムダ式のような自由と柔軟さはないが、C++03でbind1stやbind2ndを組み合わせて生成するよりはマシかもしれない。

find_pred の全体は以下の通り。

Function find_pred(ByRef pred As Variant, ByRef vec As Variant) As Variant
    Dim z As Variant
    Dim i As Long: i = LBound(vec)
    For Each z In vec
        If applyFun(z, pred) Then
            find_pred = i
            Exit Function
        End If
        i = i + 1
    Next z
    find_pred = Null
End Function

Function find_pred(ByRef pred As Variant, ByRef vec As Variant) As Variant
    If Dimension(vec) = 1 Then
        find_pred = find_imple(pred, vec, UBound(vec) + 1)
        If find_pred = UBound(vec) + 1 Then find_pred = Null
    Else
        find_pred = Null
    End If
End Function

 

個々の配列要素に対してapplyFun(z, pred) で pred を呼び出すだけである。

(2015/4/14)

効率上の理由からVBA側でループするのではなくAPIに find_imple 関数を追加してそれを呼び出す形に変更した。C++側でイテレーションのたびにpred の構築と破棄を繰り返すのは無駄だから。 

 

ところで引数の順序が find_pred(pred, vec) とするか find_pred(vec, pred) とするか決め難かった。とりあえず述語を前にしたが、ソート関連の関数*3では比較関数が後になっている。

VBAHaskellの紹介 その3 (FizzBuzz
http://mmyymmdd.hatenablog.com/entry/2015/04/11/130016
VBAHaskellの紹介 その2 (合成関数)
http://mmyymmdd.hatenablog.com/entry/2015/04/11/112139
VBAHaskellの紹介 その1 (最初はmapF)
http://mmyymmdd.hatenablog.com/entry/2015/04/11/095044

ソースコード

github.com

dllのバイナリ:
http://home.b07.itscom.net/m-yamada/VBA/mapM.dll

*1:もちろん込み入った条件を定義するには個別に関数を定義した方がいい

*2:test_moduleのSub vbaUnitにサンプルがある

*3:sortIndex_pred、lower_bound_pred、upper_bound_pred、equal_range_pred