VBAHaskellの改修まとめ
最近VBAHaskellにいくつか変更をしたのでまとめの記事を書きます。
VBAHaskell全関数リファレンス → VBAHaskell_reference
1. API関数self_zipWith
を追加しました
次のようなシグネチャの関数をHaskell_0_declare.basの一番下に追加しました。
' 1次元配列の離れた要素間で2項操作を適用する Declare PtrSafe Function self_zipWith Lib "mapM.dll" ( _ ByRef pCallback As Variant, _ ByRef vec As Variant, _ ByVal shift As Long) As Variant
名前から想像できると思いますが、2つの配列の要素間に関数を適用する zipWith
と同じようなことを、一つの配列の中で行うものです。
3番目の引数shift
に与えた数値が「いくつ要素をずらしながら処理を適用するのか」を表し、正負どちらの方向にずらしても1周して戻ってきます。
たとえば 関数f
と 配列a
(a(0)~a(9)の範囲とします)を引数にするさい、
self_zipWith(f, a, 1)
とすると
f(a(0), a(1)), f(a(1), a(2)), f(a(2), a(3)), ... , f(a(8), a(9)), f(a(9), a(0))
が、
self_zipWith(f, a, -1)
とすると
f(a(0), a(9)), f(a(1), a(0)), f(a(2), a(1)), ... , f(a(8), a(7)), f(a(9), a(8))
が戻り値になります。
printM self_zipWith(p_plus, iota(1, 10), 5) 7 9 11 13 15 7 9 11 13 15
元の配列は変更されません。
次の項目である関数get_unique
や以前からあった関数adjacent_op
の効率を高めるためにこれを作りました。
2. get_unique
関数を追加しました
misc_utility.bas に、1次元配列の重複した要素を削除する関数get_unique
を追加しました。
Public Function get_unique(ByRef vec As Variant, _ Optional ByRef comp As Variant) As Variant
第2引数comp
は等値条件を表します。隣どうしの要素をcomp
で比較した結果が1
になるものを「重複」と判定します。離れた場所にある要素は比較しないので、完全に重複を削除するためにはソート済であることが前提になります。
第2引数を省略するとp_equal
を使った場合と同じになります。元の配列は変更されません。
a = uniform_int_dist(20, 5, 15) ' [5, 15]の範囲のランダム整数を20個生成 permutate a, sortIndex(a) ' 昇順ソート printM a 7 7 8 8 9 10 10 10 10 10 11 11 12 14 14 14 15 15 15 15 printM get_unique(a) 7 8 9 10 11 12 14 15 ' ↑ 重複要素が削除されている
2次元以上の場合は以下のようにジャグ配列にする必要があります。
a = zip(uniform_int_dist(20, 5, 7), uniform_int_dist(20, 101, 103)) ' ジャグ配列 permutate a, sortIndex_pred(a, p_less_dic) ' 辞書順に昇順ソート printM_ a 5 101 5 101 5 101 5 102 5 103 5 103 6 101 6 101 6 101 6 102 6 102 6 102 6 103 7 101 7 102 7 102 7 103 7 103 7 103 7 103 printM_ get_unique(a, p_equal_dic) 5 101 5 102 5 103 6 101 6 102 6 103 7 101 7 102 7 103
3. その他の変更
equal_dic (=)
関数とnotEqual_dic (<>)
関数を追加しました。
dic は dictional の略で、辞書式比較のことを示します。二つの1次元配列の要素を順に見ていって等値かそうでないかを返します。列に対する大小関係を判定する関数less_dic (<)
,less_equal_dic (<=)
,greater_dic (>)
,greater_equal_dic (>=)
はもともと存在していましたが、この2つを新たに追加しました。
Haskell_5_sort.basp_not
関数とp_imply
関数を追加しました。
p_not
はいわゆる論理Not、p_imply
は「AならばB」の「ならば」に相当するものです。いずれも関数オブジェクトのみです。
「AならばB」は not A と B のいずれかが真の時に成り立つ命題です。
misc_utility.basp_Trim
関数を追加しました。
VBA組み込みのTrim
,LTrim
,RTrim
関数をひとまとめにしたもので、第2引数0または省略時
、1
、-1
がそれぞれに対応します。
misc_utility.bas
printM_ mapF(p_str_cat(p_str_cat("0"), "1"), mapF(p_Trim, Array(" AB C ", " EFGH ", " WXYZ "))) 0AB C1 0EFGH1 0WXYZ1
A_overlap_B
関数を追加しました。
1次元配列として表された集合AとBに対して、共通部分と非共通部分を示すフラグを出力します。
Function A_overlap_B(ByRef a As Variant, _ ByRef b As Variant, _ Optional ByRef comp As Variant) As Variant
第3引数のcomp
は大小関係を表す述語で、それぞれの集合はそれによってソート済みという前提です。
a = uniform_int_dist(20, 0, 20) ' 0から20までの正数乱数(20個) b = uniform_int_dist(20, 10, 30) ' 10から30までの正数乱数(20個) permutate a, sortIndex(a) ' a をソート permutate b, sortIndex(b) ' b をソート x = A_overlap_B(a, b) ' 第3引数省略時は p_less が使われる printM catR(a, x(0)) ' x(0) はAの各要素がBに属しているかのフラグ 0 1 3 4 8 8 9 10 11 11 11 13 14 15 17 17 17 18 19 20 0 0 0 0 0 0 0 1 0 0 0 1 0 1 1 1 1 1 0 1 printM catR(b, x(1)) ' x(1) はBの各要素がAに属しているかのフラグ 10 12 13 13 15 15 17 17 17 18 18 20 20 21 24 25 25 26 27 29 1 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0