place_fill 関数の追加(VBAHaskell)
VBAHaskellにplace_fill
という関数を追加して Haskell_2_stdFun.bas
モジュールに置いた。
1次元配列内の指定した複数の位置に関数もしくは定数値を適用して、その場所に値を埋めるものだ。
埋めたあと配列そのものをmove
して返す。
' 配列の特定位置に関数/値を適用する(値を埋めてmoveして返す) Function place_fill(ByRef vec As Variant, _ 👈 対象配列 ByRef fun As Variant, _ 👈 適用する関数または定数 ByRef indice As Variant, _ 👈 インデックス Optional ByRef souce As Variant 👈 ソース配列 ) As Variant
これまでは配列全体を処理する関数がほとんどで、こういう関数はなかった。
関数にはインデックスまたはソース配列の各要素が代入され、模式的には for ( i ∈ indice ) vec(i) = fun(i)
もしくは for ( i ∈ indice ) vec(i) = fun(source(i))
というループとなる。ただし fun
が関数でなかった場合はそれ自身が値として代入される。「インデックスまたはソース配列」というのは、source
が省略された場合はindex
自身がソース配列となるという意味だ。また、source
にvec
自身を代入することもできる。
基本的な使い方はこうだ。
' 長さ10の配列の(2, 5, 8)の位置に定数を置く printM place_fill(repeat(0, 10), 1, Array(2,5,8)) 0 0 1 0 0 1 0 0 1 0 ' 長さ10の配列の(2, 5, 8)の位置に文字列の一部分を置く printM place_fill(repeat("-", 10), p_left("abcdefghijk"), Array(2,5,8)) - - ab - - abcde - - abcdefgh -
これでFizzBuzzを書くとこうなる。
あまり短くはならないが、素直なコードになる。
m = place_fill(iota(0,100), "Fizz", mapF(p_mult(3), iota(1, 33))) m = place_fill(m, "Buzz", mapF(p_mult(5), iota(1, 20))) m = place_fill(m, "FizzBuzz", mapF(p_mult(15), iota(1, 6))) printM m, -100 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz
misc_math
に実装した素数一覧を出力する関数と組み合わせるとこういう表示もできる。
printM place_fill(iota(0, 30), "☆", primeNumbers(30)) 0 1 ☆ ☆ 4 ☆ 6 ☆ 8 9 10 ☆ 12 ☆ 14 15 16 ☆ 18 ☆ 20 21 22 ☆ 24 25 26 27 28 ☆ 30
☆の前後にその素数を付けて表示するためには、文字連結関数を引数にすればいい。
printM place_fill(iota(0,30), p_str_cat("☆"), primeNumbers(30)) 0 1 ☆2 ☆3 4 ☆5 6 ☆7 8 9 10 ☆11 12 ☆13 14 15 16 ☆17 18 ☆19 20 21 22 ☆23 24 25 26 27 28 ☆29 30 printM place_fill(iota(0,30), p_str_cat(, "☆"), primeNumbers(30)) 0 1 2☆ 3☆ 4 5☆ 6 7☆ 8 9 10 11☆ 12 13☆ 14 15 16 17☆ 18 19☆ 20 21 22 23☆ 24 25 26 27 28 29☆ 30
この関数の実装は以下の通り。
' 配列vecの指定位置に関数/値を適用する(値を埋めてmoveして返す) Function place_fill(ByRef vec As Variant, _ ByRef fun As Variant, _ ByRef indice As Variant, _ Optional ByRef souce As Variant) As Variant Dim i As Long ' souceまたはindex(souce 省略時)を埋め込む If is_bindFun(fun) Then Dim tmp As Variant If IsMissing(souce) Then ' = index tmp = mapF(fun, indice) Else tmp = mapF(fun, subV(souce, indice)) End If For i = LBound(indice) To UBound(indice) Step 1 Call swapVariant(vec(indice(i)), tmp(i)) Next i Else ' 単一の値を埋め込む For i = LBound(indice) To UBound(indice) Step 1 Call assignVar(vec(indice(i)), fun) Next i End If Call swapVariant(place_fill, vec) End Function